Skip Menu |

This queue is for tickets about the Math-BigInt CPAN distribution.

Report information
The Basics
Id: 16221
Status: resolved
Worked: 5 min
Priority: 0/
Queue: Math-BigInt

People
Owner: TELS [...] cpan.org
Requestors: bpphillips [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: (no value)
Fixed in: (no value)



Subject: overloading and foreign objects
The following test case fails: package main; use Test::More tests => 1; use Math::BigInt; my $int = Math::BigInt->new(10); my $percent = My::Percent->new(100); is($int * $percent,10); package My::Percent; sub new { my $class = shift; my $num = shift; return bless \$num, $class; } sub as_number { my $self = shift; return Math::BigInt->new($$self / 100); } sub as_string { my $self = shift; return $$self; } The bug is on line 2350 of Math::BigInt: $k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k); Should be: $k = $k->can('as_number') ? $k->as_number() : $a[0]->new($k);
On Wed Nov 30 16:42:55 2005, guest wrote: Show quoted text
> The following test case fails:> > The bug is on line 2350 of Math::BigInt: > $k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k); > > Should be: > $k = $k->can('as_number') ? $k->as_number() : $a[0]->new($k);
Thanx for your report! However, when I make the proposed change, some testcases fail, so I have to investigate what the real fix should be. Sorry for the delay! Best wishes, Tels
The code line $k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k); is bad. It doesn't do what people (most likely) think. It *looks* like it is equivalent to $k->can('as_number') ? ($k = $k->as_number()) : ($k = $a[0]->new($k)); but it isn't. The reason, I believe, is that "… = …" has *lower* precedence than "… ? … : …". From what I understand, the net result is always that $k = $a[0]->new($k). That part of Math::BigInt::objectify() should be investigated.
On Sun Jan 28 07:47:37 2007, TELS wrote: Show quoted text
> > Thanx for your report! However, when I make the proposed change, some > testcases fail, so I have to investigate what the real fix should be.
In the line in Math::BigInt::objectify() saying $k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k); the "$k = $a[0]->new($k)" is always executed. If the test "$k->can('as_number')" is true, the "$k->as_number()" is also executed, but has no effect, since $k has already been through "$k = $a[0]->new($k)". When the above line is changed to $k = $k->can('as_number') ? $k->as_number() : $a[0]->new($k); the "$k->as_number()" is executed without $k having been through "$k = $a[0]->new($k)". The tests fail, as mentioned by TELS, because "$k->as_number()" and "$a[0]->new($k)" doesn't always give the same results. So Math::Big* has inconsistent behaviour with respect to how a Math::BigSomething is converted to a Math::BigInt. For example, try to convert a Math::BigFloat to a Math::BigInt: $ perl -MMath::BigFloat -wle '$x = Math::BigFloat -> new("3.14"); print Math::BigInt -> new($x)' NaN $ perl -MMath::BigFloat -wle '$x = Math::BigFloat -> new("3.14"); print $x -> as_number()' 3 (Even Math::BigInt->new() itself isn't consistent; see http://rt.cpan.org/Public/Bug/Display.html?id=61887) I suggest that "Math::BigInt -> new()" is fixed so that it always returns the same as Math::BigSomething -> as_number(), or CORE::int(). This might cause some backwards incompatibility if people have written code depending on "Math::BigInt -> new()" returning a NaN if the input has a non-zero decimal part (which it not always does; see RT 61887), but I think it is worth it. And since we are on the doorstep of Math::BigInt version 2.00, this is a good time to make the change.
RT-Send-CC: nospam-abuse [...] bloodgate.com
The same problem appears with Math::BigFloat. Here is a test that fails: Show quoted text
________________________________________ package main; use Test::More tests => 1; use Math::BigFloat; my $float = Math::BigFloat->new(10); my $percent = My::Percent->new(100); is($float * $percent, 10); package My::Percent; sub new { my $class = shift; my $num = shift; return bless \$num, $class; } sub as_int { my $self = shift; return Math::BigInt->new($$self / 100); } sub as_float { my $self = shift; return Math::BigFloat->new($$self / 100); } sub as_string { my $self = shift; return $$self; }
________________________________________ The problem is with Math::BigInt::objectify(). The objectify() function shouldn't really be in Math::BigInt. Both Math::BigInt, Math::BigFloat, and Math::BigRat uses Math::BigInt::objectify(), but Math::BigFloat and Math::BigRat are not subclasses of Math::BigInt, so things go wrong. The objectify() function should probably have been in a common parent class for the three Math::Big* modules (together with the other common functions/methods round_mode(), upgrade(), downgrade(), ...).
The code has been changed, and the test case passes. Please close this ticket.
Fixed