Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Math::FixedPrecision and bignum clash

by mje (Curate)
on Oct 08, 2014 at 09:55 UTC ( [id://1103151]=perlquestion: print w/replies, xml ) Need Help??

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

I've come across an issue in some test code which I've reduced down. This initially came about because one test module used Math::FixedPrecision and another test module used bignum. The two were not used together until a new test was written which needed both and then stringifcation of Math::FixedPrecision started failing with Can't use an undefined value as an ARRAY reference.

The reduced version is just to simplify the problem, it serves no useful purpose. I also don't understand why "no bignum" does not fix the issue. This works:

use strict; use warnings; use Data::Dumper; { require Math::FixedPrecision; my $one = Math::FixedPrecision->new('2', 2); print Dumper($one); print Dumper("$one"); }

outputting

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

and this does not work

use strict; use warnings; use bignum; use Data::Dumper; { no bignum; require Math::FixedPrecision; my $one = Math::FixedPrecision->new('2', 2); print Dumper($one); print Dumper("$one"); }

outputting

$VAR1 = bless( { 'value' => [ 2 ], '_p' => -2, 'sign' => '+' }, 'Math::FixedPrecision' ); Can't use an undefined value as an ARRAY reference at /home/perlbrew/p +erls/perl-5.16.0/lib/5.16.0/Math/BigInt/Calc.pm line 1259.

Notice the lack of a mantissa in the second case which is actually what causes the final error in Math::BigInt::Calc. Any ideas?

Replies are listed 'Best First'.
Re: Math::FixedPrecision and bignum clash
by thanos1983 (Parson) on Oct 08, 2014 at 12:58 UTC

    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!

      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.

        Regards
        McA

        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!

      Hi,

      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.

      Regards
      McA

      The underlying problem here is that "use bignum" makes "Math::BigInt" upgrade to "Math::BigFloat", and "Math::BigFloat" upgrade to "Math::BigRat". This works globally and is not removed by "no bignum". This upgrading is the cause of numerous problems and much unexpected behaviour. I have removed this upgrading in the most recent development version of the distribution and I no longer see the issue you are experiencing.
Re: Math::FixedPrecision and bignum clash
by McA (Priest) on Oct 08, 2014 at 11:53 UTC

    Hi,

    I don't have anything concrete for your problem, but for the protocol: I get a Segmentation fault on Linux, 64bit, Perl 5.10.1. Upps!

    Probably a hint where to search for a solution.

    UPDATE: I looked at the sources to see, that Math::FixedPrecision uses Math::BigFloat in its constructor. The version on my machine is 1.60. Another look at the history and bug entries did let me try an update to the currenct version 1.9993. After that I do get the same exception as you.

    Regards
    McA

Re: Math::FixedPrecision and bignum clash
by mje (Curate) on Oct 14, 2014 at 12:14 UTC

    I should have read more before posting. Searching for bignum on metacpan.org did not return the bignum module but on search.cpan.org it does and it says:

    The entire upgrading/downgrading is still experimental and might not work as you expect or may even have bugs. You might get errors like this: Can't use an undefined value as an ARRAY reference at /usr/local/lib/perl5/5.8.0/Math/BigInt/Calc.pm line 864 This means somewhere a routine got a BigFloat/Lite but expected a BigInt (or vice versa) and the upgrade/downgrad path was missing. This is a bug, please report it so that we can fix it.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-24 04:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found