in reply to Re^2: Why am I losing accuracy?
in thread Why am I losing accuracy?

Is the following returning correct results?

# for https://perlmonks.org/?node_id=11110997 # by bliako, 08/01/2020 use strict; use warnings; use Math::BigInt; use Digest::SHA qw(sha256_hex); for(my $i=1;$i<=10;$i++){ # the sha as a hex string (no '0x' prepended) my $hexstr = sha256_hex($i); # to create a bigint from a hex string we need to prepend '0x' to +it my $digest = Math::BigInt->new('0x'.$hexstr); # specify accuracy and precision $digest->accuracy(80); $digest->precision(1); # operate print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; }
1 48635463943209834798109814161294753926839975257569795305637098542720 +658922320 1 75992912411265366872046584627023053010687461339952805165057966473001 +0295660 2 96094161643976066833367867971426158458230048495430276217795328666133 +331159860 2 15014712756871260442713729370535337259098445077410980659030520104083 +33299370 3 35293215426786447154857697798367884701614677727176325092965345248689 +205321680 3 55145649104353823679465152809949819846272933948713007957758351951076 +8833150 4 33984360982413536682390860969296307922929415152052354251133793603654 +468157320 4 53100564035021151066235720264525481129577211175081803517396552505710 +1064960 5 10818240655469999731486825095773005325907358940236581977057259273658 +4172823450 5 16903501024171874580448164212145320821730248344119659339151967615091 +27700370 6 10492023800686533720501340709024820017001830686534338836405100876796 +5015414400 6 16393787188572708938283344857851281276565360447709904431882970119994 +53365850 7 54734117258892461880478870895348100103198302433611928089023761078319 +507514450 7 85522058217019471688248235773981406411247347552518637639099626684874 +2304910 8 20075373234943686845167158285967784892467090849631486320124245130906 +619831460 8 31367770679599510695573684821824663894479829452549197375194133017041 +5934870 9 11463511883541201508393500803711559652562721115888819482889049505863 +143503290 9 17911737318033127356864845005799311957129251743576280442014139852911 +1617240 10 3359281535163583886622750554468341756416232122807515421831543601247 +6449103320 10 5248877398693099822848047741356783994400362691886742846611786876949 +44517240

Still, I would like to find out what's going on in that loop and gets stuck to 10 !!!!

bw, bliako

Replies are listed 'Best First'.
Re^4: Why am I losing accuracy?
by syphilis (Archbishop) on Jan 08, 2020 at 13:32 UTC
    Still, I would like to find out what's going on in that loop and gets stuck to 10 !!!!

    Yes - we've glossed over that and we (I, at least) should not have done so.
    My (pathetic) excuse is that Math::BigInt is low priority for me.

    Can you reproduce the behaviour ?
    I can - on Windows 7, perl-5.30.0.

    It's the use bignum (p => 1); line that causes the problem.
    Change that line to merely use bignum; and that particular problem goes away.

    Cheers,
    Rob

      I don't mean to put pressure - I just leave this here for anyone.

      both of these fail with an infinite loop printing i=10 on linux fedora 30, perl 5.28.2. 10 and 15 are the min numbers to do this.

      use bignum (p=>1); for(my $i = 1;$i->blt(15);$i->binc()){ print "i=$i\n"; }
      for(my $i = 1;$i<=10;$i++){ print "i=$i\n"; }

      this shows to me that it is not the loop or the overloaded increment but that when p=>1 it thinks that it's adding that value divided by 10 or something

      my $i = 10; print "1 i=$i\n"; $i++; print "2 i=$i\n"; $i = $i + 1; print "3 i=$i\n"; $i = $i + 2; print "4 i=$i\n"; $i = $i + 3; print "5 i=$i\n"; $i = $i + 4; print "6 i=$i\n"; $i = $i + 5; print "7 i=$i\n"; $i = $i + 6 ; print "8 i=$i\n";
      1 i=10 2 i=10 3 i=10 4 i=10 5 i=10 6 i=10 7 i=20 8 i=30

      I have filed a bug to bigint

        The maintainer of bigint replied to filing a bug:

        Here is your problem: p=>1 specifies a precision of 1. See these for comparisation: $ perl -Mbignum=p,1 -wle '$i = 1; print $i + 123456788,"\n"' 123456790 $ perl -Mbignum=p,2 -wle '$i = 1; print $i + 123456788,"\n"' 123456800 $ perl -Mbignum=p,5 -wle '$i = 1; print $i + 123456788,"\n"' 123500000 Looks to me it works as designed. Here is the same with different accuracy values: $ perl -Mbignum=a,1 -wle '$i = 1; print $i + 123456788,"\n"' 100000000 $ perl -Mbignum=a,2 -wle '$i = 1; print $i + 123456788,"\n"' 120000000 $ perl -Mbignum=a,3 -wle '$i = 1; print $i + 123456788,"\n"' 123000000 and with negative values of p: $ perl -Mbignum=p,-3 -wle '$i = 1; print $i + 123456789.1,"\n"' 123456790.100 $ perl -Mbignum=p,-6 -wle '$i = 1; print $i + 123456789.1,"\n"' 123456790.100000 Best regards, Tels
Re^4: Why am I losing accuracy?
by Anonymous Monk on Jan 08, 2020 at 22:33 UTC
    Is the following returning correct results?

    Not exactly (a small loss of precision at the very end of each number). As I noted above, the output (for 1) should consist of:

    4863546394320983479810981416129475392683997525756979530563709854272065 +8922315 7599291241126536687204658462702305301068746133995280516505796647300102 +95661

    Still, better than my first attempt. :)

      ooopsy! I was sidetracked by totally misunderstood a previous comment thinking that these are whole-number divisions(=right shifts) like dividing by 10. Anyway, in this case the solution is to substitute Math::BigInt with Math::BigFloat in my previous post. Then you get the right result. BTW in Linux the command bc does arbitrary precision arithmetic and can be used to verify these numbers.

      But why not use Math::GMPz as syphilis suggested and given that unexplained, to me, loop-incrementing bug.

      bw, bliako

        > BTW in Linux the command bc does arbitrary precision arithmetic and can be used to verify these numbers.

        That was what I used. :) Further, the whole point of the script I was writing that led to this question was the desire to automate a process where I used bc, and then processed the output further. The (now-completed) perl script does everything in one step.

      Not exactly (a small loss of precision at the very end of each number).

      I think bliako's script works flawlessly if "accuracy" and "precision" are not specified:
      use strict; use warnings; use Math::BigInt; use Digest::SHA qw(sha256_hex); for(my $i=1;$i<=10;$i++){ # the sha as a hex string (no '0x' prepended) my $hexstr = sha256_hex($i); # to create a bigint from a hex string we need to prepend '0x' to +it my $digest = Math::BigInt->new('0x'.$hexstr); # operate print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; }
      Outputs:
      1 48635463943209834798109814161294753926839975257569795305637098542720 +658922315 1 75992912411265366872046584627023053010687461339952805165057966473001 +0295661 2 96094161643976066833367867971426158458230048495430276217795328666133 +331159861 2 15014712756871260442713729370535337259098445077410980659030520104083 +33299372 3 35293215426786447154857697798367884701614677727176325092965345248689 +205321678 3 55145649104353823679465152809949819846272933948713007957758351951076 +8833151 4 33984360982413536682390860969296307922929415152052354251133793603654 +468157322 4 53100564035021151066235720264525481129577211175081803517396552505710 +1064958 5 10818240655469999731486825095773005325907358940236581977057259273658 +4172823453 5 16903501024171874580448164212145320821730248344119659339151967615091 +27700366 6 10492023800686533720501340709024820017001830686534338836405100876796 +5015414403 6 16393787188572708938283344857851281276565360447709904431882970119994 +53365850 7 54734117258892461880478870895348100103198302433611928089023761078319 +507514449 7 85522058217019471688248235773981406411247347552518637639099626684874 +2304913 8 20075373234943686845167158285967784892467090849631486320124245130906 +619831459 8 31367770679599510695573684821824663894479829452549197375194133017041 +5934866 9 11463511883541201508393500803711559652562721115888819482889049505863 +143503287 9 17911737318033127356864845005799311957129251743576280442014139852911 +1617238 10 3359281535163583886622750554468341756416232122807515421831543601247 +6449103317
      Cheers,
      Rob

        Perhaps, misunderstanding began with

        I think you need to set the precision to 1

        which maybe stemmed from

        p or precision ... 0 or 1 mean round to integer

        which (i.e., Perl core module documentation) is wrong. "0" is "round to integer". "1" is not.

        Allowing "accuracy" and "precision" for extended integers (through a pragma i.e. infecting everything which interacts with source code literals!) is, simply, very evil and can lead to bizarre infinite loops, as shown, but it's not a bug in itself, because documented (but should never be used (?))