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

Greetings all, I came across a peculiarity in my travels. Ponder the following snippet:
perl -e '$a = 4_294_967_296;printf("%d %f\n", $a, $a / (1024**3))'
What I find interesting is that perl is able to do the math correctly on the large number, but is unable to display it. If anything, I'd expect the opposite behavior (being able to print, but not being able to do arithmetic on it). Thoughts?

Just curious,
thor

Replies are listed 'Best First'.
•Re: Arithmetic on numbers bigger than 1<<31
by merlyn (Sage) on May 13, 2004 at 15:51 UTC
    If you change your first %d to %f, you'll see that it also can display it correctly as well. You've asked for the impossible: display this number as a decimal integer, when it's larger than any integer on your machine. However, Perl knows that, and converts the first integer constant immediately to a floating-point value, which is carried forward for the rest of the calculation. At no time except for your coercion was it ever an integer.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Arithmetic on numbers bigger than 1<<31
by kvale (Monsignor) on May 13, 2004 at 16:07 UTC
    If you want to work with big integers, try Math::BigInt, a pure perl module, or Math::BigInt::GMP, an XS module:
    use Math::BigInt; # or make it faster: install (optional) Math::BigInt::GMP # and always use (it will fall back to pure Perl if the # GMP library is not installed): use Math::BigInt lib => 'GMP'; my $str = '1234567890'; $x = Math::BigInt->new($str); # defaults to 0 $y = $x->copy(); # make a true copy $x->badd($y); # addition (add $y to $x) $x->bsub($y); # subtraction (subtract $y from $x) $x->bstr(); # convert to a normalized string $x->bsstr(); # normalized string in scientific no +tation $x->as_hex(); # as signed hexadecimal string with +prefixed 0x $x->as_bin(); # as signed binary string with prefi +xed 0b # etc.

    -Mark

      No need to resort to "big int" modules if you only need 10 digits. Every version of Perl can do arithmatic with exact precision on integers at least to 15 digits. If you divide and wish to get an integer result, then use int which removes the fractional part of the number but doesn't truncate the value to fit in an IV.

      That is, a C data type of "double" (NV) can handle integers (and rather large ones at that) quite well and Perl does this. And Perl's int() doesn't convert to a C data type like "int" or "long" (IV).

      - tye        

Re: Arithmetic on numbers bigger than 1<<31
by flyingmoose (Priest) on May 13, 2004 at 19:27 UTC
    It can "do math" on it, presumably because the value just overflows... I doubt the value is correct.

    Use should consider using BigInt/BigFloat for very large numbers, as if you get too many significant digits normal floating point math is going to lose accuracy...but of course there is a speed tradeoff.

      But that's the thing: it is doing at least some things correctly. I wanted to see what would happen with this code:
      perl -le 'print $i+=100_000_000 while 1'
      ...and it takes it like a champ, not reaching "Infinity" until something like 1e315. Also, this looks right, too:
      perl -le 'print (((1<<31)**(1<<5)), " ",((1<<31)**(1<<5)/2))'
      So, perl is somehow doing the arithmetic...maybe it's just lucky. :)

      thor

      p.s. This whole thing was more of a curiosity than anything. I've used Math::BigInt before. I was just perplexed by something that I would have expected not to work.
Re: Arithmetic on numbers bigger than 1<<31
by zude (Scribe) on May 13, 2004 at 22:40 UTC
    The problem is that the "%d" implies a conversion to a bitwise integer,and IMHO perl is extremely broken in this regard.

    Anything larger than 2**32-1 is converted to 2**32-1 (aka -1).

    Anything smaller than -2**31 is converted to 2**31 (aka -2**31).

    Nothing else works this way. Certainly not libm.

    Whatever, it can really screw you if you aren't careful:

    (0xFFFFFFFF+1)&0xFFFFFFFF == 0xFFFFFFFF and die "Database wiped\n" Database wiped
    I hate it when that happens.