Artichoke has asked for the wisdom of the Perl Monks concerning the following question:

Whilst trying to discover the next higher power of two of a number I tried messing with bitshifting:
$tmp = @ARGV[0]; $i = 0; while( $tmp ) { $tmp >>= 1; $i += 1; } print 1 << $i;
Which works for input up till 2147483647.
Any better ideas for larger numbers. (Preferably built in rather than CPANing it.)

Note to self: remember to bring Hacker's Delight to work... TIA

Replies are listed 'Best First'.
Re: Bitshift limits
by Abigail-II (Bishop) on Nov 27, 2002 at 11:23 UTC
    Well, you could of course build yourself a 64bit perl, then you can go up to 9223372036854775807. Or else, you can use Math::BigInt. Or Inline::BC.

    Here's an Inline::BC solution:

    use strict; use warnings; use Inline 'BC'; my @nums = qw /0 1 5 10 16 2147483647 9223372036854775807 124897514814098457204985981709857243095827435/; foreach my $number (@nums) { print "$number: ", np ($number); } __DATA__ __BC__ define np (i) { auto j; while (i) { i /= 2; j += 1; } return (2 ^ j) } 0: 1 1: 2 5: 8 10: 16 16: 32 2147483647: 2147483648 9223372036854775807: 9223372036854775808 124897514814098457204985981709857243095827435: 17840596158824498513228 +5746181186892047843328

    And here's a Math::BigInt one:

    use strict; use warnings; use Math::BigInt; my @nums = qw /0 1 5 10 16 2147483647 9223372036854775807 124897514814098457204985981709857243095827435/; foreach my $number (@nums) { $number = Math::BigInt -> new ($number); my $result = Math::BigInt -> new (1); print "$number: "; until ($number == 0) { $number /= 2; $result *= 2; } print "$result\n"; } __END__ 0: 1 1: 2 5: 8 10: 16 16: 32 2147483647: 2147483648 9223372036854775807: 9223372036854775808 124897514814098457204985981709857243095827435: 17840596158824498513228 +5746181186892047843328

    Abigail

(tye)Re: Bitshift limits
by tye (Sage) on Nov 27, 2002 at 17:11 UTC

    Just change ">>= 1" to "/= 2" plus similar changes to get:

    $tmp = @ARGV[0]; $i = 0; while( 1 <= $tmp ) { $tmp /= 2; $i += 1; } print 2 ** $i;
    and you are good up to about 52 bits (instead of 32), probably quite a bit farther (depends exactly how the round-off enters into the calculations). I didn't get even a one-bit error until I tried that on 36028797018963967 (which returned twice of one more than that number, instead of just one more than that number).

    I'd do this more like:

    sub nextpow2 { my $s= shift(@_); my $p= 1; $p *= 2 while $p <= $s; return $p; }
    which exhibits the same problem but only because you can't represent 36028797018963967 exactly as a floating point number.

    So this works for quite high powers of two provided your input isn't just under a large power of two.

            - tye (don't fear the floating point)
Re: Bitshift limits
by BrowserUk (Patriarch) on Nov 27, 2002 at 11:05 UTC

    Math:BigInt (which comes as part of mystandard distribution AS 5.6.1) supports left and right shifts (to any base as well). These numbers are essencially limited only by your memory space - but don't try doing intereactive graphics with them, cos they can be a tad slow. :^)


    Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
    Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
    Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
    Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

Re: Bitshift limits
by gjb (Vicar) on Nov 27, 2002 at 11:05 UTC

    You could always buy some hardware with a 64-bit processor ;-)

    Seriously now, if you want to do anything with the large number you obtain, you'll have little choice but to reimplement part of the Math::BigInt module. Even if you manage to produce it, performing any calculation with it simply won't work without special routines for arithmic.

    I'd go with the module mentioned above if I were you. Hope this helps, -gjb-