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

I am not very experienced with perl and this test I am doing has me stumped, it appears to be rounding off numbers. Code:

use strict; use warnings; use Math::BigInt; my @CRCTable; $CRCTable[0] = Math::BigInt->new("0x3243bcfe21ef4468"); $CRCTable[1] = Math::BigInt->new("0xef453276bdbde566"); $CRCTable[2] = Math::BigInt->new("0x2342ed65876ab55f"); for (my $i=0; $i<3; $i++) { printf("%X\n",$CRCTable[$i]); }

Output is:

3243BCFE21EF4400 EF453276BDBDE800 2342ED65876AB600

Why the 2 trailing zeros ?

Replies are listed 'Best First'.
Re: Rounding off ? (updated)
by haukex (Archbishop) on Sep 13, 2018 at 22:38 UTC

    I can't reproduce that here, I'm getting the output:

    3243BCFE21EF4468 EF453276BDBDE566 2342ED65876AB55F

    Maybe you're on a 32-bit build of Perl?* Also, what version of Perl are you on? Maybe you could post the output of perl -V here.

    Anyway, yes, it's possible you're seeing some rounding effects, although I'm not sure exactly what since I can't see it here. printf is probably numifying the object into a regular Perl number, which may not be large enough to hold the value*. However, Math::BigInt provides the as_hex method:

    use warnings; use strict; use Math::BigInt; my @CRCTable = ( Math::BigInt->new("0x3243bcfe21ef4468"), Math::BigInt->new("0xef453276bdbde566"), Math::BigInt->new("0x2342ed65876ab55f"), ); for my $crc (@CRCTable) { print $crc->as_hex, "\n"; } __END__ 0x3243bcfe21ef4468 0xef453276bdbde566 0x2342ed65876ab55f

    * Update: Based on the replies I have to revise my guess: maybe you are doing some operations on the BitInts that you haven't shown here? Are you certain that the output you've posted here is exactly what you get when you run the exact code you've posted here? If yes, maybe there's something different about your build of Perl. In addition to the output of perl -V, please show the output of perl -MMath::BigInt -le 'print $Math::BigInt::VERSION'.

      FWIW, I get exactly the same output with that code. This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level.

      Maybe you're on a 32-bit build of Perl?

      On a 32-bit Perl(v5.20.1, i586-linux-thread-multi) i get:

      FFFFFFFF
      FFFFFFFF
      FFFFFFFF

      while on a 64-bit Perl(v5.28.0, x86_64-linux-thread-multi) I also get:

      3243BCFE21EF4468
      EF453276BDBDE566
      2342ED65876AB55F


        On a 32-bit Perl(v5.20.1, i586-linux-thread-multi) i get:

        FFFFFFFF
        FFFFFFFF
        FFFFFFFF

        Thanks for checking, I can confirm that result on a 32-bit Perl 5.14 on Windows. Also thanks to Your Mother and hippo for checking.

      Another for getting the same output.

      $ perl 1222321.pl 3243BCFE21EF4468 EF453276BDBDE566 2342ED65876AB55F $ perl -v | head -3 This is perl 5, version 20, subversion 3 (v5.20.3) built for x86_64-li +nux-thread-multi (with 16 registered patches, see perl -V for more detail) $ pmv Math::BigInt 1.9993
      In addition to the output of perl -V, please show the output of perl -MMath::BigInt -le 'print $Math::BigInt::VERSION'

      Yes, I think we really need this information from Zomalaja before we can make any sense of it.
      It seems very odd (to me, at least) that printf's %X formatting should be outputting 54-bit precision values.

      Cheers,
      Rob
      perl -v : This is perl, v5.10.1 (*) built for amd64-freebsd perl -MMath::BigInt -le 'print $Math::BigInt::VERSION' : 1.89 Fix was: printf("%08X%08X\n",$CRCTable[$i] >> 32,($CRCTable[$i] & 0xFFFFFFFF));

      This is a shell box that I 'rent' so it is unlikely that it will be updated. Thanks to everyone for their replies - Zomalaja

Re: Rounding off ?
by Anonymous Monk on Sep 14, 2018 at 15:26 UTC

    Somehow, your BigInts are transformed into double-precision floating point numbers before being handed to printf:

    $ tcc -run - #include <inttypes.h> #include <stdint.h> #include <stdio.h> int main(void) { printf("%" PRIx64 "\n", (uint64_t)(double)0x3243bcfe21ef4468ULL); return 0; } ^D 3243bcfe21ef4400
    But you can use as_hex() of Math::BigInt (also available in new versions: to_hex()) to get the original hex representation back:
    $ perl -MMath::BigInt -E'say Math::BigInt->new("0x3243bcfe21ef4468")-> +as_hex' 0x3243bcfe21ef4468

      printf("%" PRIx64 "\n", (uint64_t)(double)0x3243bcfe21ef4468ULL);

      Nice explanation - thanks.
      The integer values being output for the OP appeared to be 54-bit precision, and that threw me somewhat.
      But I was excluding only the trailing zero bits from the precision count, while I should also have been excluding the leading zero bits.

      It all makes sense now ... for some definition of "makes sense" ;-)

      Cheers,
      Rob
        Actually, it was your reply that triggered something in my head ("hmm, isn't it doubles that contain fifty something bits of the fraction?") and made me investigate.