From: Rafael Garcia-Suarez Date: Sun, 20 Mar 2005 21:20:50 +0000 (+0000) Subject: Upgrade to Math::BigInt 1.75, by Tels X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=a87115f0a1b74f765307464de281024d76c71ad6;p=p5sagit%2Fp5-mst-13.2.git Upgrade to Math::BigInt 1.75, by Tels p4raw-id: //depot/perl@24048 --- diff --git a/lib/Math/BigFloat.pm b/lib/Math/BigFloat.pm index 7466472..8143175 100644 --- a/lib/Math/BigFloat.pm +++ b/lib/Math/BigFloat.pm @@ -12,7 +12,7 @@ package Math::BigFloat; # _a : accuracy # _p : precision -$VERSION = '1.48'; +$VERSION = '1.49'; require 5.005; require Exporter; @@ -1340,19 +1340,25 @@ sub bdiv $scale = $ly if $ly > $scale; my $diff = $ly - $lx; $scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx! - - # cases like $x /= $x (but not $x /= $y!) were wrong due to modifying $x - # twice below) - require Scalar::Util; - if (Scalar::Util::refaddr($x) == Scalar::Util::refaddr($y)) + + # already handled inf/NaN/-inf above: + + my $xsign = $x->{sign}; + $y->{sign} =~ tr/+-/-+/; + my $y_not_one = !$y->is_one(); # cache this result + if ($xsign ne $x->{sign}) { - $x->bone(); # x/x => 1, rem 0 + # special case of $x /= $x results in 1 + $x->bone(); } else { - + # correct $y's sign again + $y->{sign} =~ tr/+-/-+/; + # continue with normal div code: + # make copy of $x in case of list context for later reminder calculation - if (wantarray && !$y->is_one()) + if (wantarray && $y_not_one) { $rem = $x->copy(); } @@ -1360,7 +1366,7 @@ sub bdiv $x->{sign} = $x->{sign} ne $y->sign() ? '-' : '+'; # check for / +-1 ( +/- 1E0) - if (!$y->is_one()) + if ($y_not_one) { # promote BigInts and it's subclasses (except when already a BigFloat) $y = $self->new($y) unless $y->isa('Math::BigFloat'); @@ -1397,7 +1403,7 @@ sub bdiv if (wantarray) { - if (!$y->is_one()) + if ($y_not_one) { $rem->bmod($y,@params); # copy already done } @@ -2736,12 +2742,33 @@ it is rounded. The rounding mode taken is either the default mode, or the one supplied to the operation after the I: $x = Math::BigFloat->new(2); - Math::BigFloat->precision(5); # 5 digits max - $y = $x->copy()->bdiv(3); # will give 0.66666 - $y = $x->copy()->bdiv(3,6); # will give 0.666666 - $y = $x->copy()->bdiv(3,6,'odd'); # will give 0.666667 + Math::BigFloat->accuracy(5); # 5 digits max + $y = $x->copy()->bdiv(3); # will give 0.66667 + $y = $x->copy()->bdiv(3,6); # will give 0.666667 + $y = $x->copy()->bdiv(3,6,undef,'odd'); # will give 0.666667 Math::BigFloat->round_mode('zero'); - $y = $x->copy()->bdiv(3,6); # will give 0.666666 + $y = $x->copy()->bdiv(3,6); # will also give 0.666667 + +Note that C<< Math::BigFloat->accuracy() >> and C<< Math::BigFloat->precision() >> +set the global variables, and thus B newly created number will be subject +to the global rounding. This means that in the examples above, the C<3> +as argument to C will also get an accuracy of B<5>. + +It is less confusing to either calculate the result fully, and afterwards +round it explicitely, or use the additional parameters to the math +functions like so: + + use Math::BigFloat; + $x = Math::BigFloat->new(2); + $y = $x->copy()->bdiv(3); + print $y->bround(5),"\n"; # will give 0.66667 + + or + + use Math::BigFloat; + $x = Math::BigFloat->new(2); + $y = $x->copy()->bdiv(3,5); # will give 0.66667 + print "$y\n"; =head2 Rounding diff --git a/lib/Math/BigInt.pm b/lib/Math/BigInt.pm index f7ff612..1d31534 100644 --- a/lib/Math/BigInt.pm +++ b/lib/Math/BigInt.pm @@ -18,7 +18,7 @@ package Math::BigInt; my $class = "Math::BigInt"; require 5.005; -$VERSION = '1.74'; +$VERSION = '1.75'; @ISA = qw( Exporter ); @EXPORT_OK = qw( objectify bgcd blcm); @@ -75,7 +75,9 @@ use overload 'cos' => sub { cos($_[0]->numify()) }, 'sin' => sub { sin($_[0]->numify()) }, 'exp' => sub { exp($_[0]->numify()) }, -'atan2' => sub { atan2($_[0]->numify(),$_[1]) }, +'atan2' => sub { $_[2] ? + atan2($_[1],$_[0]->numify()) : + atan2($_[0]->numify(),$_[1]) }, # are not yet overloadable #'hex' => sub { print "hex"; $_[0]; }, @@ -90,8 +92,8 @@ use overload # for subtract it's a bit tricky to not modify b: b-a => -a+b '-' => sub { my $c = $_[0]->copy; $_[2] ? - $c->bneg()->badd( $_[1]) : - $c->bsub( $_[1]) }, + $c->bneg()->badd( $_[1]) : + $c->bsub( $_[1]) }, '+' => sub { $_[0]->copy()->badd($_[1]); }, '*' => sub { $_[0]->copy()->bmul($_[1]); }, @@ -1146,15 +1148,17 @@ sub bsub return $x->round(@r) if $y->is_zero(); - require Scalar::Util; - if (Scalar::Util::refaddr($x) == Scalar::Util::refaddr($y)) + # To correctly handle the lone special case $x->bsub($x), we note the sign + # of $x, then flip the sign from $y, and if the sign of $x did change, too, + # then we caught the special case: + my $xsign = $x->{sign}; + $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN + if ($xsign ne $x->{sign}) { - # if we get the same variable twice, the result must be zero (the code - # below fails in that case) - return $x->bzero(@r) if $x->{sign} =~ /^[+-]$/; + # special case of $x->bsub($x) results in 0 + return $x->bzero(@r) if $xsign =~ /^[+-]$/; return $x->bnan(); # NaN, -inf, +inf } - $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN $x->badd($y,@r); # badd does not leave internal zeros $y->{sign} =~ tr/+\-/-+/; # refix $y (does nothing for NaN) $x; # already rounded by badd() or no round necc. @@ -2471,7 +2475,7 @@ sub import { if (($WARN{$lib}||0) < 2) { - my $ver = eval "\$$lib\::VERSION"; + my $ver = eval "\$$lib\::VERSION" || 'unknown'; require Carp; Carp::carp ("Cannot load outdated $lib v$ver, please upgrade"); $WARN{$lib} = 2; # never warn again diff --git a/lib/Math/BigInt/Calc.pm b/lib/Math/BigInt/Calc.pm index 39a0435..eb5ba98 100644 --- a/lib/Math/BigInt/Calc.pm +++ b/lib/Math/BigInt/Calc.pm @@ -15,7 +15,7 @@ $VERSION = '0.45'; # automatically at loading time to be the maximum possible value # todo: -# - fully remove funky $# stuff (maybe) +# - fully remove funky $# stuff in div() (maybe - that code scares me...) # USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used # instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms diff --git a/lib/Math/BigInt/t/bare_mbi.t b/lib/Math/BigInt/t/bare_mbi.t index bf08a90..b171e93 100644 --- a/lib/Math/BigInt/t/bare_mbi.t +++ b/lib/Math/BigInt/t/bare_mbi.t @@ -26,7 +26,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 3012; + plan tests => 3014; } use Math::BigInt lib => 'BareCalc'; diff --git a/lib/Math/BigInt/t/bigintpm.inc b/lib/Math/BigInt/t/bigintpm.inc index 2a2bfe1..82d0cb2 100644 --- a/lib/Math/BigInt/t/bigintpm.inc +++ b/lib/Math/BigInt/t/bigintpm.inc @@ -1633,6 +1633,8 @@ inf:0:inf 9999999_9999999_9999999_9999999:100_0000000_0000000_0000000:99999 9999999_9999999_9999999_9999999:10_0000000_0000000_0000000:999999 9999999_9999999_9999999_9999999:1_0000000_0000000_0000000:9999999 +# bug with shortcut in Calc 0.44 +949418181818187070707070707070707070:181818181853535353535353535353535353:5 &bmodinv # format: number:modulus:result # bmodinv Data errors diff --git a/lib/Math/BigInt/t/bigintpm.t b/lib/Math/BigInt/t/bigintpm.t index 16f4d32..9923256 100755 --- a/lib/Math/BigInt/t/bigintpm.t +++ b/lib/Math/BigInt/t/bigintpm.t @@ -10,7 +10,7 @@ BEGIN my $location = $0; $location =~ s/bigintpm.t//; unshift @INC, $location; # to locate the testing files chdir 't' if -d 't'; - plan tests => 3012; + plan tests => 3014; } use Math::BigInt; diff --git a/lib/Math/BigInt/t/fallback.t b/lib/Math/BigInt/t/fallback.t index e348d92..00f1dfd 100644 --- a/lib/Math/BigInt/t/fallback.t +++ b/lib/Math/BigInt/t/fallback.t @@ -28,11 +28,11 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 8; + plan tests => 12; } # The tests below test that cos(BigInt) = cos(Scalar) which is DWIM, but not -# exactly right, ideally cos(BigInt) should truncate to int() and cos(BigFLoat) +# exactly right, ideally cos(BigInt) should truncate to int() and cos(BigFloat) # should calculate the result to X digits accuracy. For now, this is better # than die()ing... @@ -46,10 +46,16 @@ ok (sin($bi), sin(1)); ok (exp($bi), exp(1)); ok (atan2($bi,$bi), atan2(1,1)); -my $bf = Math::BigInt->new(1); +my $bf = Math::BigInt->new(0); -ok (cos($bf), cos(1)); -ok (sin($bf), sin(1)); -ok (exp($bf), exp(1)); -ok (atan2($bf,$bf), atan2(1,1)); +ok (cos($bf), cos(0)); +ok (sin($bf), sin(0)); +ok (exp($bf), exp(0)); +ok (atan2($bi,$bf), atan2(1,0)); +ok (atan2($bf,$bi), atan2(0,1)); + +my $bone = Math::BigInt->new(1); +ok (cos($bone), cos(1)); +ok (sin($bone), sin(1)); +ok (exp($bone), exp(1)); diff --git a/lib/Math/BigInt/t/mbi_rand.t b/lib/Math/BigInt/t/mbi_rand.t index dd28051..d24920f 100644 --- a/lib/Math/BigInt/t/mbi_rand.t +++ b/lib/Math/BigInt/t/mbi_rand.t @@ -28,6 +28,12 @@ my $length = 128; my $seed = ($#ARGV == 0) ? $ARGV[0] : int(rand(1165537)); print "# seed: $seed\n"; srand($seed); +print "# lib: ", Math::BigInt->config()->{lib},"\n"; +if (Math::BigInt->config()->{lib} =~ /::Calc/) + { + print "# base len: ", scalar Math::BigInt::Calc->_base_len(),"\n"; + } + my ($A,$B,$As,$Bs,$ADB,$AMB,$la,$lb); my $two = Math::BigInt->new(2); for (my $i = 0; $i < $count; $i++) @@ -46,9 +52,9 @@ for (my $i = 0; $i < $count; $i++) $As =~ s/^0+//; $Bs =~ s/^0+//; $As = $As || '0'; $Bs = $Bs || '0'; - # print "# As $As\n# Bs $Bs\n"; +# print "# As $As\n# Bs $Bs\n"; $A = $c->new($As); $B = $c->new($Bs); - # print "# A $A\n# B $B\n"; + print "# A $A\n# B $B\n"; if ($A->is_zero() || $B->is_zero()) { for (1..4) { ok (1,1); } next; @@ -59,22 +65,28 @@ for (my $i = 0; $i < $count; $i++) # $X = ($A/$B)*$B + 2 * ($A % $B) - ($A % $B); ($ADB,$AMB) = $A->copy()->bdiv($B); -# print "# ($A / $B, $A % $B ) = $ADB $AMB\n"; + print "# ($A / $B, $A % $B ) = $ADB $AMB\n"; print "# seed $seed, ". join(' ',Math::BigInt::Calc->_base_len()),"\n". "# tried $ADB * $B + $two*$AMB - $AMB\n" unless ok ($ADB*$B+$two*$AMB-$AMB,$As); - print "# seed: $seed, \$ADB * \$B / \$B = ", $ADB * $B / $B, " != $ADB (\$B=$B)\n" - unless ok ($ADB*$B/$B,$ADB); + if (ok ($ADB*$B/$B,$ADB)) + { + print "# seed: $seed, \$ADB * \$B / \$B = ", $ADB * $B / $B, " != $ADB (\$B=$B)\n"; + if (Math::BigInt->config()->{lib} =~ /::Calc/) + { + print "# ADB->[-1]: ", $ADB->{value}->[-1], " B->[-1]: ", $B->{value}->[-1],"\n"; + } + } # swap 'em and try this, too # $X = ($B/$A)*$A + $B % $A; ($ADB,$AMB) = $B->copy()->bdiv($A); - #print "check: $ADB $AMB"; + # print "check: $ADB $AMB"; print "# seed $seed, ". join(' ',Math::BigInt::Calc->_base_len()),"\n". "# tried $ADB * $A + $two*$AMB - $AMB\n" unless ok ($ADB*$A+$two*$AMB-$AMB,$Bs); -# print " +$two * $AMB = ",$ADB * $A + $two * $AMB,"\n"; -# print " -$AMB = ",$ADB * $A + $two * $AMB - $AMB,"\n"; + print "# +$two * $AMB = ",$ADB * $A + $two * $AMB,"\n"; + print "# -$AMB = ",$ADB * $A + $two * $AMB - $AMB,"\n"; print "# seed $seed, \$ADB * \$A / \$A = ", $ADB * $A / $A, " != $ADB (\$A=$A)\n" unless ok ($ADB*$A/$A,$ADB); } diff --git a/lib/Math/BigInt/t/sub_mbi.t b/lib/Math/BigInt/t/sub_mbi.t index 4d4fc4e..9346dcd 100755 --- a/lib/Math/BigInt/t/sub_mbi.t +++ b/lib/Math/BigInt/t/sub_mbi.t @@ -26,7 +26,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 3012 + plan tests => 3014 + 5; # +5 own tests }