Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Why am I losing accuracy?

by Anonymous Monk
on Jan 05, 2020 at 18:57 UTC ( [id://11110997]=perlquestion: print w/replies, xml ) Need Help??

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

Trying to use bignum (obviously), which I have never used before. I thought that once I had a variable as a extra precision number, it would stay that way. It seems I need to specify something else, but exactly what remains elusive to me.

#!/usr/bin/perl -w use strict; use bignum; use Digest::SHA qw(sha256_hex); my $i = 1; my $digest = hex(sha256_hex($i)); # just for debugging print "$digest\n"; $digest /= 64; print "$digest\n"; 4863546394320983479810981416129475392683997525756979530563709854272065 +8922315 7599291241126536687204658462702305301069000000000000000000000000000000 +00000
I expected to see:
4863546394320983479810981416129475392683997525756979530563709854272065 +8922315 7599291241126536687204658462702305301068746133995280516505796647300102 +95661

Replies are listed 'Best First'.
Re: Why am I losing accuracy?
by haukex (Archbishop) on Jan 05, 2020 at 19:34 UTC

    See the Math::BigInt docs in regards to its div_scale parameter: "This is the accuracy used when neither accuracy nor precision is set explicitly. It is used when a computation might otherwise attempt to return an infinite number of digits." The default value is 40, which is what you're seeing there.

    You can either pass an accuracy to the bdiv method explicitly, for example: $digest = $digest->bdiv(64, 1000)->as_int;, or perhaps do this instead: use Math::BigRat; Math::BigRat->new($digest, 64)->as_int;, both of these result in your desired answer. (There are probably one or two other methods but these are the first I've thought of.)

      Could also use $digest->brsft(6); (since 64 is 26)

Re: Why am I losing accuracy?
by bliako (Monsignor) on Jan 07, 2020 at 12:33 UTC

    Why not keep it simple and use Math::BigInt or Math::BigFloat only for those variables who need it? (and not for ALL, e.g. loop variable $i)?

    In fact, ikegami points that all you are doing is right shifts. So, probably you need BigInt (or a simple substr!). Sorry this is not what was suggested, I misunderstood that the default base for brsft() is 2, so it is not a right shift on base 10, i.e. $digest /= 64

    bw, bliako

      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.
        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.

        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

Re: Why am I losing accuracy?
by ForgotPasswordAgain (Priest) on Jan 05, 2020 at 19:31 UTC

      I am definitely into things I don't understand here. :(

      #!/usr/bin/perl -w use strict; use bignum; use Digest::SHA qw(sha256_hex); # a small expansion on the previous code block for (my $i = 1; $i <= 9; $i++) { my $digest = hex(sha256_hex($i)); print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; } 1 48635463943209834798109814161294753926839975257569795305637098542720 +658922315 1 75992912411265366872046584627023053010690000000000000000000000000000 +0000000 2 96094161643976066833367867971426158458230048495430276217795328666133 +331159861 2 15014712756871260442713729370535337259100000000000000000000000000000 +00000000 3 35293215426786447154857697798367884701614677727176325092965345248689 +205321678 3 55145649104353823679465152809949819846270000000000000000000000000000 +0000000 4 33984360982413536682390860969296307922929415152052354251133793603654 +468157322 4 53100564035021151066235720264525481129580000000000000000000000000000 +0000000 5 10818240655469999731486825095773005325907358940236581977057259273658 +4172823453 5 16903501024171874580448164212145320821730000000000000000000000000000 +00000000 6 10492023800686533720501340709024820017001830686534338836405100876796 +5015414403 6 16393787188572708938283344857851281276570000000000000000000000000000 +00000000 7 54734117258892461880478870895348100103198302433611928089023761078319 +507514449 7 85522058217019471688248235773981406411250000000000000000000000000000 +0000000 8 20075373234943686845167158285967784892467090849631486320124245130906 +619831459 8 31367770679599510695573684821824663894480000000000000000000000000000 +0000000 9 11463511883541201508393500803711559652562721115888819482889049505863 +143503287 9 17911737318033127356864845005799311957130000000000000000000000000000 +0000000

      I start getting incorrect mathematical calculations here.

      #!/usr/bin/perl -w use strict; # changed only this line use bignum (p => 1); use Digest::SHA qw(sha256_hex); for (my $i = 1; $i <= 9; $i++) { my $digest = hex(sha256_hex($i)); print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; } 1 48635463943209834798109814161294753926839975257569795305637098542720 +658922315 1 81059106572016391330183023602157923211399958762616325509395164237867 +7648705 2 96094161643976066833367867971426158458230048495430276217795328666133 +331159861 2 16015693607329344472227977995237693076371674749238379369632554777688 +88852664 3 35293215426786447154857697798367884701614677727176325092965345248689 +205321678 3 58822025711310745258096162997279807836024462878627208488275575414482 +0088695 4 33984360982413536682390860969296307922929415152052354251133793603654 +468157322 4 56640601637355894470651434948827179871549025253420590418556322672757 +4469289 5 10818240655469999731486825095773005325907358940236581977057259273658 +4172823453 5 18030401092449999552478041826288342209845598233727636628428765456097 +36213724 6 10492023800686533720501340709024820017001830686534338836405100876796 +5015414403 6 17486706334477556200835567848374700028336384477557231394008501461327 +50256907 7 54734117258892461880478870895348100103198302433611928089023761078319 +507514449 7 91223528764820769800798118158913500171997170722686546815039601797199 +1791907 8 20075373234943686845167158285967784892467090849631486320124245130906 +619831459 8 33458955391572811408611930476612974820778484749385810533540408551511 +0330524 9 11463511883541201508393500803711559652562721115888819482889049505863 +143503287 9 19105853139235335847322501339519266087604535193148032471481749176438 +5725055

      And here, things have really gone off of the rails.

      #!/usr/bin/perl -w use strict; use bignum (p => 1); use Digest::SHA qw(sha256_hex); # here, I change 9 to 10 for (my $i = 1; $i <= 10; $i++) { my $digest = hex(sha256_hex($i)); print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; } 1 48635463943209834798109814161294753926839975257569795305637098542720 +658922315 1 81059106572016391330183023602157923211399958762616325509395164237867 +7648705 2 96094161643976066833367867971426158458230048495430276217795328666133 +331159861 2 16015693607329344472227977995237693076371674749238379369632554777688 +88852664 3 35293215426786447154857697798367884701614677727176325092965345248689 +205321678 3 58822025711310745258096162997279807836024462878627208488275575414482 +0088695 4 33984360982413536682390860969296307922929415152052354251133793603654 +468157322 4 56640601637355894470651434948827179871549025253420590418556322672757 +4469289 5 10818240655469999731486825095773005325907358940236581977057259273658 +4172823453 5 18030401092449999552478041826288342209845598233727636628428765456097 +36213724 6 10492023800686533720501340709024820017001830686534338836405100876796 +5015414403 6 17486706334477556200835567848374700028336384477557231394008501461327 +50256907 7 54734117258892461880478870895348100103198302433611928089023761078319 +507514449 7 91223528764820769800798118158913500171997170722686546815039601797199 +1791907 8 20075373234943686845167158285967784892467090849631486320124245130906 +619831459 8 33458955391572811408611930476612974820778484749385810533540408551511 +0330524 9 11463511883541201508393500803711559652562721115888819482889049505863 +143503287 9 19105853139235335847322501339519266087604535193148032471481749176438 +5725055 10 3359281535163583886622750554468341756416232122807515421831543601247 +6449103317 10 5598802558605973144371250924113902927360386871345859036385906002079 +40818389 10 3359281535163583886622750554468341756416232122807515421831543601247 +6449103317 10 5598802558605973144371250924113902927360386871345859036385906002079 +40818389 10 3359281535163583886622750554468341756416232122807515421831543601247 +6449103317 10 5598802558605973144371250924113902927360386871345859036385906002079 +40818389 [repeats indefinitely]
        I am definitely into things I don't understand here

        I, too, don't know why it repeats indefinitely, but I can confirm that I see the same behaviour.

        If you want something that DWIMs nicely, and works quickly and reliably, I would suggest using either Math::GMPz or Math::GMP.
        Either will do, though they both require the GMP C library:
        #!/usr/bin/perl -w use strict; use Math::GMPz; # use Math::GMP; use Digest::SHA qw(sha256_hex); for (my $i = 1; $i <= 10; $i++) { my $digest = Math::GMPz->new(sha256_hex($i), 16); # my $digest = Math::GMP-> new(sha256_hex($i), 16); print "$i $digest\n"; $digest /= 64; print "$i $digest\n"; }
        Output is:
        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 10 5248877398693099822848047741356783994400362691886742846611786876949 +44517239
        Cheers,
        Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11110997]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2024-04-20 11:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found