bignum::bdiv() not working correctly on integers

J

jl_post

Hi,

I've recently discovered that if I create a "bignum" object in Perl
and call the ->bdiv() method, sometimes the object will get modified
and sometimes it won't. Here's a sample program that illustrates what
I'm talking about:

#!/usr/bin/perl

use strict;
use warnings;

use bignum;

my $n1 = 6.6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6.6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3.3

print "\n";

my $n2 = 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 6 (error?)

__END__


I've tested this script on both Windows and Unix, and the output is
the same. I changed "use bignum" to "use bigint" and I saw the
expected 6, 3, and 6, 3 as output. (The floating-point numbers were
truncated, but that's no surprise since we're working with integers.)

I also changed "bdiv" to "bmul" (using the "bignum" module) and I
saw the expected 6.6, 13.2, and 6, 12 as output, so apparently
bignum::dmul() works consistently.

I've noticed that bignum::bdiv() seems to modify the calling object
if the value is a floating-point number (that is, cannot be
represented as an integer). But if the calling object is an integer
(even one with a decimal point like 6.0), then bignum::bdiv() does not
modify it.

I noticed that if I print out ref($n1) and ref($n2), I see that $n1
is a Math::BigFloat and that $n2 is a Math::BigInt. So I might think
that the problem lies in the Math::BigInt module. However, when I
change "use bignum" to "use bigint", they both become Math::BigInt
objects, but now the bdiv() method is modifying the calling object (as
I think it should).

So it doesn't look like the problem is with Math::BigInt, but
rather with the "bignum" module.

Is this incosistent behavior of the "bignum" module a bug, or am I
missing something? I haven't seen much code that uses the "bigint"
and "bignum" modules, so as far as I know they're deprecated, but I
haven't read anything to that effect.

-- Jean-Luc
 
S

Steve C

Hi,

I've recently discovered that if I create a "bignum" object in Perl
and call the ->bdiv() method, sometimes the object will get modified
and sometimes it won't. Here's a sample program that illustrates what
I'm talking about:

#!/usr/bin/perl

use strict;
use warnings;

use bignum;

my $n1 = 6.6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6.6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3.3

print "\n";

my $n2 = 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 6 (error?)

__END__


I've tested this script on both Windows and Unix, and the output is
the same. I changed "use bignum" to "use bigint" and I saw the
expected 6, 3, and 6, 3 as output. (The floating-point numbers were
truncated, but that's no surprise since we're working with integers.)

I also changed "bdiv" to "bmul" (using the "bignum" module) and I
saw the expected 6.6, 13.2, and 6, 12 as output, so apparently
bignum::dmul() works consistently.

I've noticed that bignum::bdiv() seems to modify the calling object
if the value is a floating-point number (that is, cannot be
represented as an integer). But if the calling object is an integer
(even one with a decimal point like 6.0), then bignum::bdiv() does not
modify it.

I noticed that if I print out ref($n1) and ref($n2), I see that $n1
is a Math::BigFloat and that $n2 is a Math::BigInt. So I might think
that the problem lies in the Math::BigInt module. However, when I
change "use bignum" to "use bigint", they both become Math::BigInt
objects, but now the bdiv() method is modifying the calling object (as
I think it should).

So it doesn't look like the problem is with Math::BigInt, but
rather with the "bignum" module.

Is this incosistent behavior of the "bignum" module a bug, or am I
missing something? I haven't seen much code that uses the "bigint"
and "bignum" modules, so as far as I know they're deprecated, but I
haven't read anything to that effect.

-- Jean-Luc

bigint promotes the type to BigInt or BigFloat as required.
When you start with a BigInt and divide by a float it must make
a new bignum. You can see it explicitly by doing this:

my $n1 = new Math::BigFloat 6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3

print "\n";

my $n2 = new Math::BigInt 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 6 (unexpected)
 
J

jl_post

bigint promotes the type to BigInt or BigFloat as required.
When you start with a BigInt and divide by a float it must make
a new bignum. You can see it explicitly by doing this:

my $n1 = new Math::BigFloat 6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3

print "\n";

my $n2 = new Math::BigInt 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 6 (unexpected)


That's not the behavior I'm getting. When I run your code in the
following script:


#!/usr/bin/perl

use strict;
use warnings;

use Math::BigFloat;
my $n1 = new Math::BigFloat 6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3

print "\n";

use Math::BigInt;
my $n2 = new Math::BigInt 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 3

__END__


I see as output 6, 3 and 6, 3 (and not 6, 3, and 6, 6 like you saw).

But even if Math::BigInt::bdiv() did make a new bignum, I'd still
expect the bdiv() method to behave as documented in the "perldoc
Math::BigInt" documentation, which is to change the value of the
calling object.

I noticed that just placing the "use bignum;" like anywhere in the
script causes weird things to happen. Even if I put it in as the last
line of my above script (but before the __END__ tag, of course) the
output I see changes to 6, 6 and 6, 6.

Did you have "use bignum;" (or "use bigint;") anywhere in your
script? If you do, try removing it and running the script again. You
might get different output.

And in case anyone wants to know, "perl -v" gives me this output:

On Windows: This is perl, v5.10.0 built for MSWin32-x86-multi-thread

On Linux: This is perl, v5.8.4 built for i386-linux-thread-multi

-- Jean-Luc
 
S

Steve C

That's not the behavior I'm getting. When I run your code in the
following script:


#!/usr/bin/perl

use strict;
use warnings;

use Math::BigFloat;
my $n1 = new Math::BigFloat 6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3

print "\n";

use Math::BigInt;
my $n2 = new Math::BigInt 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 3

__END__


I see as output 6, 3 and 6, 3 (and not 6, 3, and 6, 6 like you saw).

But even if Math::BigInt::bdiv() did make a new bignum, I'd still
expect the bdiv() method to behave as documented in the "perldoc
Math::BigInt" documentation, which is to change the value of the
calling object.

I noticed that just placing the "use bignum;" like anywhere in the
script causes weird things to happen. Even if I put it in as the last
line of my above script (but before the __END__ tag, of course) the
output I see changes to 6, 6 and 6, 6.

Did you have "use bignum;" (or "use bigint;") anywhere in your
script? If you do, try removing it and running the script again. You
might get different output.

And in case anyone wants to know, "perl -v" gives me this output:

On Windows: This is perl, v5.10.0 built for MSWin32-x86-multi-thread

On Linux: This is perl, v5.8.4 built for i386-linux-thread-multi

-- Jean-Luc

I was explaining what bignum does. Math::BigInt and Math::BigFloat
act as expected by themselves. Sorry I forgot to include the
use bignum in my post.
 
J

jl_post

I was explaining what bignum does.  Math::BigInt and Math::BigFloat
act as expected by themselves.  Sorry I forgot to include the
use bignum in my post.


Okay, but if I run my most-recently posted script with "use
bignum;" I get 6, 6 and 6, 6. If I run it without that line I see 6,
3, and 6, 3. I still don't see how you got 6, 3, and 6, 6.

Can you post the script you used?

-- Jean-Luc
 
S

Steve C

Okay, but if I run my most-recently posted script with "use
bignum;" I get 6, 6 and 6, 6. If I run it without that line I see 6,
3, and 6, 3. I still don't see how you got 6, 3, and 6, 6.

Can you post the script you used?

-- Jean-Luc


use bignum;

my $n1 = new Math::BigFloat 6;
print "\$n1 before \$n1->bdiv(2): $n1\n"; # prints 6
$n1->bdiv(2);
print "\$n1 after \$n1->bdiv(2): $n1\n"; # prints 3

print "\n";

my $n2 = new Math::BigInt 6;
print "\$n2 before \$n2->bdiv(2): $n2\n"; # prints 6
$n2->bdiv(2);
print "\$n2 after \$n2->bdiv(2): $n2\n"; # prints 6
 
J

jl_post

bigint promotes the type to BigInt or BigFloat as required.
When you start with a BigInt and divide by a float it must make
a new bignum.

I disagree. When I run this code:


#!/usr/bin/perl
use strict;
use warnings;

use Math::BigInt;
my $n = Math::BigInt->new(6);

print "\$n before \$n->bdiv(2): $n\n"; # prints 6
print "\\\$n = ", \$n, "\n";
print "ref(\$n) = ", ref($n), "\n\n";
$n->bdiv(2);
print "\$n after \$n->bdiv(2): $n\n"; # prints 3
print "\\\$n = ", \$n, "\n";
print "ref(\$n) = ", ref($n), "\n";
__END__


I see this output:

$n before $n->bdiv(2): 6
\$n = REF(0x22c725c)
ref($n) = Math::BigInt

$n after $n->bdiv(2): 3
\$n = REF(0x22c725c)
ref($n) = Math::BigInt

So not only do I see 6 and 3 as output, I also see that $n is still
the same object before as after the call to ->bdiv() (in other words,
it never made a copy).

Now I run the following script, which is identical to the previous
one except that it has the "use bignum;" line at the bottom:


#!/usr/bin/perl
use strict;
use warnings;

use Math::BigInt;
my $n = Math::BigInt->new(6);

print "\$n before \$n->bdiv(2): $n\n"; # prints 6
print "\\\$n = ", \$n, "\n";
print "ref(\$n) = ", ref($n), "\n\n";
$n->bdiv(2);
print "\$n after \$n->bdiv(2): $n\n"; # prints 6 (why?)
print "\\\$n = ", \$n, "\n";
print "ref(\$n) = ", ref($n), "\n";

use bignum;
__END__


Now I get this output:

$n before $n->bdiv(2): 6
\$n = REF(0x99725c)
ref($n) = Math::BigInt

$n after $n->bdiv(2): 6
\$n = REF(0x99725c)
ref($n) = Math::BigInt

As before, $n is still the same object (that is, it was not
replaced with a copy) and it's still a Math::BigInt object, but now
the output is 6 and 6.

Why is that? Why is just the simple inclusion of the "use bignum;"
line enough to change the behavior of Math::BigInt::bdiv() ?

"perldoc Math::BigInt" explicitly says that $n will be modified
when calling the bdiv() method. If that's the case, why does the
first script do just that but the second script does not? (There's
nothing I found in the "perldoc bignum" documentation that says
otherwise.)

-- Jean-Luc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top