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

Hello Monks,

I get different results for formatted printing of big numbers between Slackware 13.37 x86_64 (real PC):
  - perl 5, version 12, subversion 3 (v5.12.3) built for x86_64-linux-thread-multi
and all three of:
Slackware 13.37 32bit (running as a VMWare Player guest)
  - perl 5, version 12, subversion 3 (v5.12.3) built for i486-linux-thread-multi
Windows XP Home Edition Service Pack 3 (build 2600) 32bit (running as a VMWare Player guest)
  - (ActivePerl) perl 5, version 12, subversion 4 (v5.12.4) built for MSWin32-x86-multi-thread
  - (Strawberry Perl) perl 5, version 12, subversion 3 (v5.12.3) built for MSWin32-x86-multi-thread

I suppose it's related to "use bignum;" and 32bit.

The results on the 32bit OSs print correctly for big numbers when using a simple "print" statement. But when I try formatted printing using printf, or using print on a string produced by sprintf, then the values are wrong for big numbers (> 2**32 - 1). The problem occurs with all non-floating point formats I tried: binary (%b), octal (%o), hex (%h) and int (%u).
I also printed out in scientific (%e) and floating point (%f) - they are correct.

Code and results are below. Anybody any ideas?

Cheers, Peter

#!/usr/bin/perl use warnings; use strict; use bignum; my $i = 10; &format_and_print; $i = 4300000000; &format_and_print; sub format_and_print { print "i: $i\n"; my $ibytes = sprintf("%b", $i); print "print ibytes : $ibytes\n"; printf("printf ibytes: %s\n", $ibytes); my $ioctal = sprintf("%o", $i); print "print ioctal : $ioctal\n"; printf("printf ioctal: %s\n", $ioctal); my $ihex = sprintf("%x", $i); print "print ihex : $ihex\n"; printf("printf ihex : %s\n", $ihex); my $isci = sprintf("%e", $i); print "print isci : $isci\n"; printf("printf isci : %s\n", $isci); my $ifloat = sprintf("%f", $i); print "print ifloat : $ifloat\n"; printf("printf ifloat: %s\n", $ifloat); my $iint = sprintf("%u", $i); print "print iint : $iint\n"; printf("printf iint : %s\n\n", $iint); } exit;
All 3 of Win XP 32bit ActivePerl, Win XP 32bit Strawberry Perl and Slackware 13.37 32 bit give identical incorrect results (for big numbers > 2**32 - 1):
i: 10 print ibytes : 1010 printf ibytes: 1010 print ioctal : 12 printf ioctal: 12 print ihex : a printf ihex : a print isci : 1.000000e+01 printf isci : 1.000000e+01 print ifloat : 10.000000 printf ifloat: 10.000000 print iint : 10 printf iint : 10 i: 4300000000 print ibytes : 11111111111111111111111111111111 printf ibytes: 11111111111111111111111111111111 print ioctal : 37777777777 printf ioctal: 37777777777 print ihex : ffffffff printf ihex : ffffffff print isci : 4.300000e+09 printf isci : 4.300000e+09 print ifloat : 4300000000.000000 printf ifloat: 4300000000.000000 print iint : 4294967295 printf iint : 4294967295
Slackware 13.37 x86_64 correct results:
i: 10 print ibytes : 1010 printf ibytes: 1010 print ioctal : 12 printf ioctal: 12 print ihex : a printf ihex : a print isci : 1.000000e+01 printf isci : 1.000000e+01 print ifloat : 10.000000 printf ifloat: 10.000000 print iint : 10 printf iint : 10 i: 4300000000 print ibytes : 100000000010011001100101100000000 printf ibytes: 100000000010011001100101100000000 print ioctal : 40023145400 printf ioctal: 40023145400 print ihex : 1004ccb00 printf ihex : 1004ccb00 print isci : 4.300000e+09 printf isci : 4.300000e+09 print ifloat : 4300000000.000000 printf ifloat: 4300000000.000000 print iint : 4300000000 printf iint : 4300000000

Replies are listed 'Best First'.
Re: bignum with (s)printf - 64bit OS OK, 32bit incorrect. What to do?
by Anonymous Monk on Jul 01, 2011 at 16:52 UTC
    There is nothing you can do. s/printf is the interface to the c runtimes s/printf function, and it doesn't know anything about bignum.

    Probably, bignum, might have its own s/printf function, or a way to format numbers

      I believe you are right about the cause.

      According to the docs, Math::BigInt doesn't have a full printf method. Nor does bigint have one, even though it can overload the global hex function so it could conceivably overload sprintf as well, but that wouldn't be easy to implement.

      What Math::BigInt has is the methods bstr, as_hex, as_oct, as_bin to format an integer as decimal, hexadecimal, octal and binary respectively. For example,

      use bignum; say+(3**100)->as_hex;
      will output 3**100 in hexadecimal, which comes out as
      0x5a4653ca673768565b41f775d6947d55cf3813d1

      (If you wanted a full printf function that works on bignums, you could use Math::GMPz, though of course it will only work with Math::GMPz objects, you can't directly pass a Math::BigInt object to it.)

Re: bignum with (s)printf - 64bit OS OK, 32bit incorrect. What to do?
by Marshall (Canon) on Jul 01, 2011 at 21:01 UTC
    I would suggest reading BigInt Math docs in addition to BigInt Main docs. A BigInt is an object.
    #!/usr/bin/perl -w use strict; use bignum; use Math::BigInt; my $i = Math::BigInt->new(4300000000); print $i->as_bin(), "\n"; #prints 0b100000000010011001100101100000000 my $j = 4300000000; print $j->as_bin(), "\n"; #also prints 0b100000000010011001100101100000000
    ActiveState Perl 5.10.1 on Win XP 32 bit
      Thank 'ee. That'll do nicely.
      And have read as suggested, too!
      Cheers,
      Peter