Change 33666 by [EMAIL PROTECTED] on 2008/04/11 10:53:40
Subject: [PATCH] Math::BigRat 0.22
From: Tels <[EMAIL PROTECTED]>
Date: Mon, 7 Apr 2008 21:27:30 +0200
Message-Id: <[EMAIL PROTECTED]>
Affected files ...
... //depot/perl/MANIFEST#1692 edit
... //depot/perl/lib/Math/BigRat.pm#21 edit
... //depot/perl/lib/Math/BigRat/t/biglog.t#2 edit
... //depot/perl/lib/Math/BigRat/t/bigrat.t#13 edit
... //depot/perl/lib/Math/BigRat/t/bigroot.t#2 edit
... //depot/perl/lib/Math/BigRat/t/hang.t#1 add
Differences ...
==== //depot/perl/MANIFEST#1692 (text) ====
Index: perl/MANIFEST
--- perl/MANIFEST#1691~33643~ 2008-04-03 10:14:51.000000000 -0700
+++ perl/MANIFEST 2008-04-11 03:53:40.000000000 -0700
@@ -2127,6 +2127,7 @@
lib/Math/BigRat/t/bigrat.t Math::BigRat test
lib/Math/BigRat/t/bigratup.t test under $Math::BigInt::upgrade
lib/Math/BigRat/t/bigroot.t Math::BigRat test
+lib/Math/BigRat/t/hang.t Math::BigRat test for bug #34584 - hang
in exp()
lib/Math/BigRat/t/requirer.t see if require works properly
lib/Math/BigRat/t/trap.t see if trap_nan and trap_inf work
lib/Math/Complex.pm A Complex package
==== //depot/perl/lib/Math/BigRat.pm#21 (text) ====
Index: perl/lib/Math/BigRat.pm
--- perl/lib/Math/BigRat.pm#20~31875~ 2007-09-16 03:48:40.000000000 -0700
+++ perl/lib/Math/BigRat.pm 2008-04-11 03:53:40.000000000 -0700
@@ -23,7 +23,7 @@
@ISA = qw(Math::BigFloat);
-$VERSION = '0.21';
+$VERSION = '0.22';
use overload; # inherit overload from Math::BigFloat
@@ -937,6 +937,13 @@
return $x->round(@r) if $x->is_zero(); # 0**y => 0 (if not y <= 0)
+ # shortcut if y == 1/N (is then sqrt() respective broot())
+ if ($MBI->_is_one($y->{_n}))
+ {
+ return $x->bsqrt(@r) if $MBI->_is_two($y->{_d}); # 1/2 => sqrt
+ return $x->broot($MBI->_str($y->{_d}),@r); # 1/N => root(N)
+ }
+
# shortcut y/1 (and/or x/1)
if ($MBI->_is_one($y->{_d}))
{
@@ -974,21 +981,18 @@
return $x->round(@r);
}
- # regular calculation (this is wrong for d/e ** f/g)
- my $pow2 = $self->bone();
- my $y1 = $MBI->_div ( $MBI->_copy($y->{_n}), $y->{_d});
- my $two = $MBI->_two();
-
- while (!$MBI->_is_one($y1))
- {
- $pow2->bmul($x) if $MBI->_is_odd($y1);
- $MBI->_div($y1, $two);
- $x->bmul($x);
- }
- $x->bmul($pow2) unless $pow2->is_one();
- # n ** -x => 1/n ** x
- ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-';
- $x->bnorm()->round(@r);
+# print STDERR "# $x $y\n";
+
+ # otherwise:
+
+ # n/d n ______________
+ # a/b = -\/ (a/b) ** d
+
+ # (a/b) ** n == (a ** n) / (b ** n)
+ $MBI->_pow($x->{_n}, $y->{_n} );
+ $MBI->_pow($x->{_d}, $y->{_n} );
+
+ return $x->broot($MBI->_str($y->{_d}),@r); # n/d => root(n)
}
sub blog
@@ -1020,21 +1024,21 @@
sub bexp
{
# set up parameters
- my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
- ($self,$x,$y,$a,$p,$r) = objectify(2,$class,@_);
+ ($self,$x,$y,@r) = objectify(2,$class,@_);
}
- return $x->binf() if $x->{sign} eq '+inf';
- return $x->bzero() if $x->{sign} eq '-inf';
+ return $x->binf(@r) if $x->{sign} eq '+inf';
+ return $x->bzero(@r) if $x->{sign} eq '-inf';
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my ($scale,@params);
- ($x,@params) = $x->_find_round_parameters($a,$p,$r);
+ ($x,@params) = $x->_find_round_parameters(@r);
# also takes care of the "error in _find_round_parameters?" case
return $x if $x->{sign} eq 'NaN';
@@ -1043,11 +1047,11 @@
if (scalar @params == 0)
{
# simulate old behaviour
- $params[0] = $self->div_scale(); # and round to it as accuracy
- $params[1] = undef; # P = undef
- $scale = $params[0]+4; # at least four more for proper round
- $params[2] = $r; # round mode by caller or undef
- $fallback = 1; # to clear a/p afterwards
+ $params[0] = $self->div_scale(); # and round to it as accuracy
+ $params[1] = undef; # P = undef
+ $scale = $params[0]+4; # at least four more for proper round
+ $params[2] = $r[2]; # round mode by caller or undef
+ $fallback = 1; # to clear a/p afterwards
}
else
{
@@ -1165,7 +1169,7 @@
if ($a != 0 || !$MBI->_is_one($x->{_d}))
{
# n/d
- return Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv(
$MBI->_str($x->{_d}), $x->accuracy());
+ return scalar Math::BigFloat->new($x->{sign} .
$MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
}
# just n
Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
@@ -1187,7 +1191,7 @@
}
# do it with floats
- $x->_new_from_float( $x->_as_float()->broot($y,@r) );
+ $x->_new_from_float( $x->_as_float()->broot($y->_as_float(),@r)
)->bnorm()->bround(@r);
}
sub bmodpow
@@ -1418,6 +1422,28 @@
$u;
}
+sub as_float
+ {
+ # return N/D as Math::BigFloat
+
+ # set up parameters
+ my ($self,$x,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ ($self,$x,@r) = objectify(1,$class,@_) unless ref $_[0];
+
+ # NaN, inf etc
+ return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
+
+ my $u = Math::BigFloat->bzero();
+ $u->{sign} = $x->{sign};
+ # n
+ $u->{_m} = $MBI->_copy($x->{_n});
+ $u->{_e} = $MBI->_zero();
+ $u->bdiv( $MBI->_str($x->{_d}), @r);
+ # return $u
+ $u;
+ }
+
sub as_bin
{
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
@@ -1655,7 +1681,7 @@
Returns the object as a scalar. This will lose some data if the object
cannot be represented by a normal Perl scalar (integer or float), so
-use as_int() instead.
+use L<as_int()> or L<as_float()> instead.
This routine is automatically used whenever a scalar is required:
@@ -1672,6 +1698,19 @@
C<as_number()> is an alias for C<as_int()>.
+=head2 as_float()
+
+ $x = Math::BigRat->new('13/7');
+ print $x->as_float(),"\n"; # '1'
+
+ $x = Math::BigRat->new('2/3');
+ print $x->as_float(5),"\n"; # '0.66667'
+
+Returns a copy of the object as BigFloat, preserving the
+accuracy as wanted, or the default of 40 digits.
+
+This method was added in v0.22 of Math::BigRat (April 2008).
+
=head2 as_hex()
$x = Math::BigRat->new('13');
@@ -1933,6 +1972,10 @@
works only for values that a marked with a C<RW> above, anything else is
read-only.
+=head2 objectify()
+
+This is an internal routine that turns scalars into objects.
+
=head1 BUGS
Some things are not yet implemented, or only implemented half-way:
@@ -1969,6 +2012,6 @@
=head1 AUTHORS
-(C) by Tels L<http://bloodgate.com/> 2001 - 2007.
+(C) by Tels L<http://bloodgate.com/> 2001 - 2008.
=cut
==== //depot/perl/lib/Math/BigRat/t/biglog.t#2 (text) ====
Index: perl/lib/Math/BigRat/t/biglog.t
--- perl/lib/Math/BigRat/t/biglog.t#1~31629~ 2007-07-18 11:52:12.000000000
-0700
+++ perl/lib/Math/BigRat/t/biglog.t 2008-04-11 03:53:40.000000000 -0700
@@ -28,7 +28,7 @@
}
print "# INC = @INC\n";
- plan tests => 14;
+ plan tests => 17;
}
use Math::BigRat;
@@ -66,18 +66,18 @@
'90933395208605785401971970164779391644753259799242' . '/' .
'33452526613163807108170062053440751665152000000000',
'bexp(1)');
-#is ($cl->new(2)->bexp(40), $cl->new(1)->bexp(45)->bpow(2,40), 'bexp(2)');
+is ($cl->new(2)->bexp(1,40), $cl->new(1)->bexp(1,45)->bpow(2,40), 'bexp(2)');
-#is ($cl->new("12.5")->bexp(61), $cl->new(1)->bexp(65)->bpow(12.5,61),
'bexp(12.5)');
+is ($cl->new("12.5")->bexp(1,61), $cl->new(1)->bexp(1,65)->bpow(12.5,61),
'bexp(12.5)');
#############################################################################
# test bexp() with big values (non-cached)
-#is ($cl->new(1)->bexp(100),
-#
'2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427',
-# 'bexp(100)');
+is ($cl->new(1)->bexp(1,100)->as_float(100),
+
'2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427',
+ 'bexp(100)');
-is ($cl->new("12.5")->bexp(91), $cl->new(1)->bexp(95)->bpow(12.5,91),
+is ($cl->new("12.5")->bexp(1,91), $cl->new(1)->bexp(1,95)->bpow(12.5,91),
'bexp(12.5) to 91 digits');
#############################################################################
==== //depot/perl/lib/Math/BigRat/t/bigrat.t#13 (xtext) ====
Index: perl/lib/Math/BigRat/t/bigrat.t
--- perl/lib/Math/BigRat/t/bigrat.t#12~30359~ 2007-02-19 11:23:03.000000000
-0800
+++ perl/lib/Math/BigRat/t/bigrat.t 2008-04-11 03:53:40.000000000 -0700
@@ -8,7 +8,7 @@
$| = 1;
chdir 't' if -d 't';
unshift @INC, '../lib'; # for running manually
- plan tests => 193;
+ plan tests => 198;
}
# basic testing of Math::BigRat
@@ -197,8 +197,8 @@
$x = $cr->new('1/3'); $z = $x->bpow('4/1'); ok ($x,'1/81');
$x = $cr->new('2/3'); $z = $x->bpow('4/1'); ok ($x,'16/81');
-# XXX todo:
-#$x = $cr->new('2/3'); $z = $x->bpow('5/3'); ok ($x,'32/81 ???');
+$x = $cr->new('2/3'); $z = $x->bpow('5/3');
+ok ($x,
'31797617848703662994667839220546583581/62500000000000000000000000000000000000');
##############################################################################
# bfac
@@ -279,7 +279,7 @@
# square root with exact result
$x = $cr->new('1.44');
-ok ($x->copy()->broot(2), '12/10');
+ok ($x->copy()->broot(2), '6/5');
ok (ref($x->copy()->broot(2)), $cr);
# log with exact result
@@ -312,6 +312,19 @@
ok ($x, '64', 'from_oct');
##############################################################################
+# as_float()
+
+$x = Math::BigRat->new('1/2'); my $f = $x->as_float();
+
+ok ($x, '1/2', '$x unmodified');
+ok ($f, '0.5', 'as_float(0.5)');
+
+$x = Math::BigRat->new('2/3'); $f = $x->as_float(5);
+
+ok ($x, '2/3', '$x unmodified');
+ok ($f, '0.66667', 'as_float(2/3,5)');
+
+##############################################################################
# done
1;
==== //depot/perl/lib/Math/BigRat/t/bigroot.t#2 (text) ====
Index: perl/lib/Math/BigRat/t/bigroot.t
--- perl/lib/Math/BigRat/t/bigroot.t#1~31629~ 2007-07-18 11:52:12.000000000
-0700
+++ perl/lib/Math/BigRat/t/bigroot.t 2008-04-11 03:53:40.000000000 -0700
@@ -34,7 +34,7 @@
}
print "# INC = @INC\n";
- plan tests => 4 * 2;
+ plan tests => 8 * 2;
}
use Math::BigFloat;
@@ -46,11 +46,10 @@
# 2 ** 240 =
# 1766847064778384329583297500742918515827483896875618958121606201292619776
-# takes way too long
-#test_broot ('2','240', 8, undef, '1073741824');
-#test_broot ('2','240', 9, undef,
'106528681.3099908308759836475139583940127');
-#test_broot ('2','120', 9, undef,
'10321.27324073880096577298929482324664787');
-#test_broot ('2','120', 17, undef,
'133.3268493632747279600707813049418888729');
+test_broot ('2','240', 8, undef, '1073741824');
+test_broot ('2','240', 9, undef,
'106528681.3099908308759836475139583940127');
+test_broot ('2','120', 9, undef,
'10321.27324073880096577298929482324664787');
+test_broot ('2','120', 17, undef,
'133.3268493632747279600707813049418888729');
test_broot ('2','120', 8, undef, '32768');
test_broot ('2','60', 8, undef, '181.0193359837561662466161566988413540569');
==== //depot/perl/lib/Math/BigRat/t/hang.t#1 (text) ====
Index: perl/lib/Math/BigRat/t/hang.t
--- /dev/null 2008-03-18 12:45:05.529577733 -0700
+++ perl/lib/Math/BigRat/t/hang.t 2008-04-11 03:53:40.000000000 -0700
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+
+# test for bug #34584: hang in exp(1/2)
+
+use strict;
+use Test::More;
+
+BEGIN
+ {
+ $| = 1;
+ chdir 't' if -d 't';
+ unshift @INC, '../lib'; # for running manually
+ plan tests => 1;
+ }
+
+use Math::BigRat;
+
+my $result = Math::BigRat->new('1/2')->bexp();
+
+is ("$result",
"9535900335500879457687887524133067574481/5783815921445270815783609372070483523265",
+ "exp(1/2) worked");
+
+##############################################################################
+# done
+
+1;
+
End of Patch.