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

Finally got this working (thanks, all) with just the following line of code:

use bigint (a => 80);
The final code actually does division by numbers other than 64, so I can't just use shift. :) I am curious about how to assign Math::BigInt or Math::BigFloat (or bignum or bigint) only for the variables that need it. Can you enlighten me on how to do that? Thanks, again.

Replies are listed 'Best First'.
Re^3: Why am I losing accuracy?
by haukex (Archbishop) on Jan 08, 2020 at 14:16 UTC
    I am curious about how to assign Math::BigInt or Math::BigFloat (or bignum or bigint) only for the variables that need it. Can you enlighten me on how to do that?

    In that case don't use bignum;, instead use Math::BigInt; and/or use Math::BigFloat;, and then create the objects explicitly, as in my $i = Math::BigInt->new(1);. If you're done with the calculations and don't want them to be objects anymore, you can stringify them, e.g. $i = "$1"; - don't use them as numbers or you'll loose the accuracy.

Re^3: Why am I losing accuracy?
by bliako (Abbot) on Jan 08, 2020 at 13:06 UTC

    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

      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

      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

        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