Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

Re: Math::FixedPrecision and bignum clash

by thanos1983 (Parson)
on Oct 08, 2014 at 12:58 UTC ( #1103171=note: print w/replies, xml ) Need Help??

in reply to Math::FixedPrecision and bignum clash

Hello mje,

I did a bit of a research as McA did but on a different area. I came up with the following:

Ok let's start with the basics, I tried to load both Math::FixedPrecision and bignum. As a result, I got the same error with you.

Then I went I start reading for bignum and I found this:

All operators (including basic math operations) are overloaded. Integer and floating-point constants are created as proper BigInts or BigFloats, respectively.

If you do use bignum;

at the top of your script, Math::BigFloat and Math::BigInt will be loaded and any constant number will be converted to an object (Math::BigFloat for floats like 3.1415 and Math::BigInt for integers like 1234).

So at this point I can imagine there is a conflict between the packages Math::FixedPrecision and bignum.

So as a second step I decided to go through the documentation of Math::BigFloat and Math::BigInt where are used by bignum in order to create my solution to your problem.

If I understand correctly, your problem is that you want to have accuracy to the nth digit of your float, but at the same time you want to use the bignum module.

Update: I just thought that maybe you are interested in just getting the 2 digits after the dot of a float, without rounding. In that case the solution could be much more simpler by using substr. If this is what you are looking for you can simply do that:

Update 2: wrong output, correcting output. I was experimenting and accidentally I posted before the experimentation.

my $pi = "3.1415"; my $substr = substr $pi, 0, 4; print "\substring: ".$substr."\n"; # $substr: 1.14

Alternatively if my assumption is correct, sample of working code with the output:

#!/usr/bin/perl use bignum; use strict; use warnings; use Math::BigFloat; sub math { my $pi = "3.1415"; my $substr = substr $pi, 0, 4; print "\$substr: ".$substr."\n"; my $N = Math::BigFloat->new($pi); print "\$N: ".$N."\n"; my $round = $N->copy()->ffround(-3); print "\$round:" .$round. "\n"; } math(); sub alternative { my $x = 2 + 4.5; # BigFloat 6.5 print "My \$x: ".$x."\n"; print 2 ** 512 * 0.1,"\n"; # really is what you think it is print inf * inf,"\n"; # prints inf print NaN * 3,"\n"; # prints NaN { no bignum; print 2 ** 256 * 0.1,"\n"; # a normal Perl scalar now } } alternative(); __END__ $substr: 3.14 $N: 3.1415 $round:3.142 My $x: 6.5 1340780792994259709957402499820584612747936582059239337772356144372176 +403007354697680187429816690342769003185818648605085375388281194656994 +643364900608409.6 inf NaN 1.15792089237316e+76
Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re^2: Math::FixedPrecision and bignum clash
by mje (Curate) on Oct 08, 2014 at 13:21 UTC

    Thank you thanos1983 for the obvious time you've spent looking at this. I came to the same conclusion as you (and hence my title) that there is some sort of clash between Math::BigFloat/bignum and Math::FixedPrecision but Math::FixedPrecision is really only a Math::BigFloat wrapper so I don't understand that.

    I can only think using bignum causes math inside Math::FixedPrecision (of which there is very little) to use Math::BigFloats and this breaks things or more likely something else (the missing mantissa is very strange). I'd really like to know what is going on and I'll have another go at looking in to it tonight.

    Although your alternative appears to work it is not quite what Math::FixedPrecision does. ffround does bankers rounding and Math::FixedPrecision does no rounding. e.g.,

    use strict; use warnings; use Math::FixedPrecision; my $x = 3.145; my $y = Math::FixedPrecision->new($x, 2); print "$x, $y\n"; # outputs 3.145, 3.14

    If you change your 1.1415 to 1.145 you'll see the difference.

    Basically the 2 modules in question were written by 2 different people. One module only needed a dozen or so lines of code using Math::FixedPrecision. The other module was massive and had loads of math so the author chose to simplify it and use bignum. This problem only occurred when someone tried to write a test which used both.

    I have some possible solutions not that disimilar to yours but it is nagging at me as why you cannot mix the two and what is going on.

    Thanks again for looking at this, it is much appreciated.

      Hi mje,

      IMHO your assumption of rounding in Math::FixedPrecision is not true. When you have a look at the constructor of Math::FixedPrecision you'll see the the value 3.145 having 3 digits after the point will be rounded to two digits (what is given as second parameter) with ffround (line 80 of sources).

      The effect you see is caused by mathematical (odd) rounding (default of Math::BigFloat) with your example. Have a look at these two examples:

      #!/usr/bin/perl use strict; use warnings; use 5.010; use Math::FixedPrecision; my $b = Math::FixedPrecision->new(3.145, 2); say $b; # output: 3.14 my $c = Math::FixedPrecision->new(3.155, 2); say $c; # output 3.16

      UPDATE: Added output for the reader.


        Yes, thanks. I was wrong and it is using bankers rounding. Looks at the last digit being kept and if odd rounds down and even rounds up so long as first digit beyond the precision is >= 5. That is another bug in the code we're using here which does not want bankers rounding.

      Hello again mje,

      Possibly there is a conflict between the two modules, but in any case I do not think so that Math::FixedPrecision is a bad module. It can handle big float numbers just like bignum.

      Sample of code:

      #!/usr/bin/perl use strict; use warnings; use Math::FixedPrecision; my $x = 3.1415; my $y = Math::FixedPrecision->new($x, 3); print "$x, $y\n"; __END__ 3.1415, 3.142

      It seems correct since anything above or equal to .5 should round up one unit. Which I am getting the same result with bignum.

      At this point the only difference that I could find in between these two modules is that bignum also can handle big integers with precision and accuracy. It just gives you more options to play around.

      Apart from that with a quick look that I took, I can not spot other differences between them.

      Out of curiosity what is your test that you are running that you want to use both modules? As far as I can see if you use bignum you get anything you need.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re^2: Math::FixedPrecision and bignum clash
by McA (Priest) on Oct 08, 2014 at 21:59 UTC


    this problem made me so curious that I investigated a little bit more. I'm pretty sure I found a reason for the problem but not the details.

    Look at these two snippets which rebuild IMHO the code path which is taken by the initial code examples:

    #!/usr/bin/perl use strict; use warnings; use 5.010; use Data::Dumper; use Math::BigFloat; use bignum; { no bignum; require Math::BigFloat; my $one = Math::BigFloat->new('2'); print Dumper($one); print Dumper("$one"); }

    What you get is:

    $VAR1 = bless( { 'value' => [ 2 ], 'sign' => '+' }, 'Math::BigInt' ); $VAR1 = '2';

    Compare this to the output of the snippet:

    #!/usr/bin/perl use strict; use warnings; use 5.010; use Data::Dumper; use Math::BigFloat; #use bignum; { # no bignum; require Math::BigFloat; my $one = Math::BigFloat->new('2'); print Dumper($one); print Dumper("$one"); }

    which has the following output:

    $VAR1 = bless( { '_m' => [ 2 ], '_es' => '+', '_e' => [ 0 ], 'sign' => '+' }, 'Math::BigFloat' ); $VAR1 = '2';

    Do you see the relevant difference? In the first case you get a Math::BigInt object, in the second case a Math::BigFloat object.

    After that I'm pretty sure that the constructor of Math::BigFloat does have a problem together with the pragma bignum.

    Probably it's worth to file a bug against Math::BigFloat or bignum (probably not so transparent as stated). I really don't know.

    Back to the initial problem. Math::FixedPrecision inherits from Math::BigFloat and not from Math::BigInt. Besides the fact that Math::FixedPrecision uses old and depreciated features of Math::BigFloat and manipulates the internals of Math::BigFloat circumventing the API which is a total OO-mess, this intransparency is pretty sure the cause of the exception.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1103171]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2020-12-05 15:46 GMT
Find Nodes?
    Voting Booth?
    How often do you use taint mode?

    Results (64 votes). Check out past polls.