From: Rafael Garcia-Suarez Date: Mon, 21 Apr 2008 07:34:12 +0000 (+0000) Subject: Upgrade to Math::BigInt v1.89 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=0dceeee6e959c7f3d5309a27b2e2126f833803f8;p=p5sagit%2Fp5-mst-13.2.git Upgrade to Math::BigInt v1.89 p4raw-id: //depot/perl@33715 --- diff --git a/lib/Math/BigFloat.pm b/lib/Math/BigFloat.pm index 6e1ecc8..27d60b3 100644 --- a/lib/Math/BigFloat.pm +++ b/lib/Math/BigFloat.pm @@ -12,7 +12,7 @@ package Math::BigFloat; # _a : accuracy # _p : precision -$VERSION = '1.59'; +$VERSION = '1.60'; require 5.006; require Exporter; @@ -2142,8 +2142,9 @@ sub bsqrt # But we need at least $scale digits, so calculate how many are missing my $shift = $scale - $digits; - # That should never happen (we take care of integer guesses above) - # $shift = 0 if $shift < 0; + # This happens if the input had enough digits + # (we take care of integer guesses above) + $shift = 0 if $shift < 0; # Multiply in steps of 100, by shifting left two times the "missing" digits my $s2 = $shift * 2; @@ -2846,12 +2847,49 @@ sub batan2 return $y->bnan() if ($y->{sign} eq $nan) || ($x->{sign} eq $nan); - return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; - # Y X # 0 0 result is 0 # 0 +x result is 0 - return $y->bzero(@r) if $y->is_zero() && $x->{sign} eq '+'; + # ? inf result is 0 + return $y->bzero(@r) if ($x->is_inf('+') && !$y->is_inf()) || ($y->is_zero() && $x->{sign} eq '+'); + + # Y X + # != 0 -inf result is +- pi + if ($x->is_inf() || $y->is_inf()) + { + # calculate PI + my $pi = $self->bpi(@r); + if ($y->is_inf()) + { + # upgrade to BigRat etc. + return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; + if ($x->{sign} eq '-inf') + { + # calculate 3 pi/4 + $MBI->_mul($pi->{_m}, $MBI->_new(3)); + $MBI->_div($pi->{_m}, $MBI->_new(4)); + } + elsif ($x->{sign} eq '+inf') + { + # calculate pi/4 + $MBI->_div($pi->{_m}, $MBI->_new(4)); + } + else + { + # calculate pi/2 + $MBI->_div($pi->{_m}, $MBI->_new(2)); + } + $y->{sign} = substr($y->{sign},0,1); # keep +/- + } + # modify $y in place + $y->{_m} = $pi->{_m}; + $y->{_e} = $pi->{_e}; + $y->{_es} = $pi->{_es}; + # keep the sign of $y + return $y; + } + + return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; # Y X # 0 -x result is PI @@ -2859,7 +2897,7 @@ sub batan2 { # calculate PI my $pi = $self->bpi(@r); - # modify $x in place + # modify $y in place $y->{_m} = $pi->{_m}; $y->{_e} = $pi->{_e}; $y->{_es} = $pi->{_es}; @@ -2870,16 +2908,15 @@ sub batan2 # Y X # +y 0 result is PI/2 # -y 0 result is -PI/2 - if ($y->is_inf() || $x->is_zero()) + if ($x->is_zero()) { # calculate PI/2 my $pi = $self->bpi(@r); - # modify $x in place + # modify $y in place $y->{_m} = $pi->{_m}; $y->{_e} = $pi->{_e}; $y->{_es} = $pi->{_es}; # -y => -PI/2, +y => PI/2 - $y->{sign} = substr($y->{sign},0,1); # +inf => + $MBI->_div($y->{_m}, $MBI->_new(2)); return $y; } @@ -2918,7 +2955,7 @@ sub batan2 { # 1,1 => PI/4 my $pi_4 = $self->bpi( $scale - 3); - # modify $x in place + # modify $y in place $y->{_m} = $pi_4->{_m}; $y->{_e} = $pi_4->{_e}; $y->{_es} = $pi_4->{_es}; @@ -3639,6 +3676,14 @@ sub as_number return $x if $x->modify('as_number'); + if (!$x->isa('Math::BigFloat')) + { + # if the object can as_number(), use it + return $x->as_number() if $x->can('as_number'); + # otherwise, get us a float and then a number + $x = $x->can('as_float') ? $x->as_float() : $self->new(0+"$x"); + } + my $z = $MBI->_copy($x->{_m}); if ($x->{_es} eq '-') # < 0 { @@ -4146,14 +4191,19 @@ You can change this by using: use Math::BigFloat lib => 'GMP'; +B: General purpose packages should not be explicit about the library +to use; let the script author decide which is best. + Note: The keyword 'lib' will warn when the requested library could not be loaded. To suppress the warning use 'try' instead: use Math::BigFloat try => 'GMP'; -To turn the warning into a die(), use 'only' instead: +If your script works with huge numbers and Calc is too slow for them, +you can also for the loading of one of these libraries and if none +of them can be used, the code will die: - use Math::BigFloat only => 'GMP'; + use Math::BigFloat only => 'GMP,Pari'; The following would first try to find Math::BigInt::Foo, then Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: diff --git a/lib/Math/BigInt.pm b/lib/Math/BigInt.pm index 362769f..b19b3dc 100644 --- a/lib/Math/BigInt.pm +++ b/lib/Math/BigInt.pm @@ -18,7 +18,7 @@ package Math::BigInt; my $class = "Math::BigInt"; use 5.006; -$VERSION = '1.88'; +$VERSION = '1.89'; @ISA = qw(Exporter); @EXPORT_OK = qw(objectify bgcd blcm); @@ -3000,11 +3000,47 @@ sub batan2 return $y->bnan() if ($y->{sign} eq $nan) || ($x->{sign} eq $nan); - return $y->bzero() if $y->is_zero() && $x->{sign} eq '+'; # x >= 0 - - # inf handling - # +-inf => --PI/2 => +-1 - return $y->bone( substr($y->{sign},0,1) ) if $y->{sign} =~ /^[+-]inf$/; + # Y X + # != 0 -inf result is +- pi + if ($x->is_inf() || $y->is_inf()) + { + # upgrade to BigFloat etc. + return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; + if ($y->is_inf()) + { + if ($x->{sign} eq '-inf') + { + # calculate 3 pi/4 => 2.3.. => 2 + $y->bone( substr($y->{sign},0,1) ); + $y->bmul($self->new(2)); + } + elsif ($x->{sign} eq '+inf') + { + # calculate pi/4 => 0.7 => 0 + $y->bzero(); + } + else + { + # calculate pi/2 => 1.5 => 1 + $y->bone( substr($y->{sign},0,1) ); + } + } + else + { + if ($x->{sign} eq '+inf') + { + # calculate pi/4 => 0.7 => 0 + $y->bzero(); + } + else + { + # PI => 3.1415.. => 3 + $y->bone( substr($y->{sign},0,1) ); + $y->bmul($self->new(3)); + } + } + return $y; + } return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; @@ -3056,9 +3092,10 @@ Math::BigInt - Arbitrary size integer/float math package use Math::BigInt; - # or make it faster: install (optional) Math::BigInt::GMP - # and always use (it will fall back to pure Perl if the - # GMP library is not installed): + # or make it faster with huge numbers: install (optional) + # Math::BigInt::GMP and always use (it will fall back to + # pure Perl if the GMP library is not installed): + # (See also the L section!) # will warn if Math::BigInt::GMP cannot be found use Math::BigInt lib => 'GMP'; @@ -3066,6 +3103,9 @@ Math::BigInt - Arbitrary size integer/float math package # to supress the warning use this: # use Math::BigInt try => 'GMP'; + # dies if GMP cannot be loaded: + # use Math::BigInt only => 'GMP'; + my $str = '1234567890'; my @values = (64,74,18); my $n = 1; my $sign = '-'; @@ -4390,26 +4430,46 @@ instead relying on the internal representation. Math with the numbers is done (by default) by a module called C. This is equivalent to saying: - use Math::BigInt lib => 'Calc'; + use Math::BigInt try => 'Calc'; + +You can change this backend library by using: -You can change this by using: + use Math::BigInt try => 'GMP'; - use Math::BigInt lib => 'BitVect'; +B: General purpose packages should not be explicit about the library +to use; let the script author decide which is best. + +If your script works with huge numbers and Calc is too slow for them, +you can also for the loading of one of these libraries and if none +of them can be used, the code will die: + + use Math::BigInt only => 'GMP,Pari'; The following would first try to find Math::BigInt::Foo, then Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: - use Math::BigInt lib => 'Foo,Math::BigInt::Bar'; + use Math::BigInt try => 'Foo,Math::BigInt::Bar'; + +The library that is loaded last will be used. Note that this can be +overwritten at any time by loading a different library, and numbers +constructed with different libraries cannot be used in math operations +together. + +=head3 What library to use? -Since Math::BigInt::GMP is in almost all cases faster than Calc (especially in -math involving really big numbers, where it is B faster), and there is -no penalty if Math::BigInt::GMP is not installed, it is a good idea to always -use the following: +B: General purpose packages should not be explicit about the library +to use; let the script author decide which is best. - use Math::BigInt lib => 'GMP'; +L and L are in cases involving big +numbers much faster than Calc, however it is slower when dealing with very +small numbers (less than about 20 digits) and when converting very large +numbers to decimal (for instance for printing, rounding, calculating their +length in decimal etc). -Different low-level libraries use different formats to store the -numbers. You should B depend on the number having a specific format +So please select carefully what libary you want to use. + +Different low-level libraries use different formats to store the numbers. +However, you should B depend on the number having a specific format internally. See the respective math library module documentation for further details. @@ -4571,11 +4631,8 @@ modules and see if they help you. =head2 Alternative math libraries -You can use an alternative library to drive Math::BigInt via: - - use Math::BigInt lib => 'Module'; - -See L for more information. +You can use an alternative library to drive Math::BigInt. See the section +L for more information. For more benchmark results see L. diff --git a/lib/Math/BigInt/t/bare_mbf.t b/lib/Math/BigInt/t/bare_mbf.t index 53b9fb4..9bb4bce 100644 --- a/lib/Math/BigInt/t/bare_mbf.t +++ b/lib/Math/BigInt/t/bare_mbf.t @@ -27,7 +27,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 2292; + plan tests => 2308; } use Math::BigFloat lib => 'BareCalc'; diff --git a/lib/Math/BigInt/t/bare_mbi.t b/lib/Math/BigInt/t/bare_mbi.t index 6b572ee..637e695 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 => 3257; + plan tests => 3273; } use Math::BigInt lib => 'BareCalc'; diff --git a/lib/Math/BigInt/t/bigfltpm.inc b/lib/Math/BigInt/t/bigfltpm.inc index 10cfaf0..7d650e5 100644 --- a/lib/Math/BigInt/t/bigfltpm.inc +++ b/lib/Math/BigInt/t/bigfltpm.inc @@ -450,6 +450,14 @@ NaN:NaN:10:NaN 1:NaN:10:NaN inf:1:14:1.5707963267949 -inf:1:14:-1.5707963267949 +0:-inf:14:3.1415926535898 +-1:-inf:14:-3.1415926535898 +1:-inf:14:3.1415926535898 +0:inf:14:0 +inf:-inf:14:2.3561944901923 +-inf:-inf:14:-2.3561944901923 +inf:+inf:14:0.7853981633974 +-inf:+inf:14:-0.7853981633974 1:5:13:0.1973955598499 1:5:14:0.19739555984988 0:0:10:0 diff --git a/lib/Math/BigInt/t/bigfltpm.t b/lib/Math/BigInt/t/bigfltpm.t index 0956883..a41996e 100755 --- a/lib/Math/BigInt/t/bigfltpm.t +++ b/lib/Math/BigInt/t/bigfltpm.t @@ -26,7 +26,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 2292 + plan tests => 2308 + 5; # own tests } diff --git a/lib/Math/BigInt/t/bigintpm.inc b/lib/Math/BigInt/t/bigintpm.inc index 53c6629..87140ba 100644 --- a/lib/Math/BigInt/t/bigintpm.inc +++ b/lib/Math/BigInt/t/bigintpm.inc @@ -2304,6 +2304,15 @@ NaN:NaN:10:NaN 1:NaN:10:NaN inf:1:14:1 -inf:1:14:-1 +0:-inf:14:3 +-1:-inf:14:-3 +1:-inf:14:3 +0:inf:14:0 +inf:-inf:14:2 +-inf:-inf:14:-2 +# +- 0.78.... +inf:+inf:14:0 +-inf:+inf:14:0 1:5:13:0 1:5:14:0 0:0:10:0 diff --git a/lib/Math/BigInt/t/bigintpm.t b/lib/Math/BigInt/t/bigintpm.t index 9442fbb..b4f5bf2 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 => 3257 + 6; + plan tests => 3273 + 6; } use Math::BigInt lib => 'Calc'; diff --git a/lib/Math/BigInt/t/calling.t b/lib/Math/BigInt/t/calling.t index 3fee915..4789cc7 100644 --- a/lib/Math/BigInt/t/calling.t +++ b/lib/Math/BigInt/t/calling.t @@ -32,11 +32,6 @@ BEGIN print "# INC = @INC\n"; my $tests = 160; plan tests => $tests; - if ($] < 5.006) - { - for (1..$tests) { skip (1,'Not supported on older Perls'); } - exit; - } } package Math::BigInt::Test; diff --git a/lib/Math/BigInt/t/const_mbf.t b/lib/Math/BigInt/t/const_mbf.t index be86407..a73177e 100644 --- a/lib/Math/BigInt/t/const_mbf.t +++ b/lib/Math/BigInt/t/const_mbf.t @@ -29,11 +29,6 @@ BEGIN print "# INC = @INC\n"; plan tests => 2; - if ($] < 5.006) - { - for (1..2) { skip (1,'Not supported on older Perls'); } - exit; - } } use Math::BigFloat ':constant'; diff --git a/lib/Math/BigInt/t/constant.t b/lib/Math/BigInt/t/constant.t index 8df7283..3e69bae 100644 --- a/lib/Math/BigInt/t/constant.t +++ b/lib/Math/BigInt/t/constant.t @@ -27,11 +27,6 @@ BEGIN print "# INC = @INC\n"; plan tests => 7; - if ($] < 5.006) - { - for (1..7) { skip (1,'Not supported on older Perls'); } - exit; - } } use Math::BigInt ':constant'; diff --git a/lib/Math/BigInt/t/mbimbf.t b/lib/Math/BigInt/t/mbimbf.t index fae3c8c..1ac9ada 100644 --- a/lib/Math/BigInt/t/mbimbf.t +++ b/lib/Math/BigInt/t/mbimbf.t @@ -32,7 +32,7 @@ BEGIN print "# INC = @INC\n"; plan tests => 684 - + 23; # own tests + + 26; # own tests } use Math::BigInt 1.70; @@ -100,3 +100,11 @@ $x = Math::BigFloat->new(100); $x = $x->blog(Math::BigInt->new(10)); ok ($x,2); + +# bug until v1.88 for sqrt() with enough digits +for my $i (80,88,100) + { + $x = Math::BigFloat->new("1." . ("0" x $i) . "1"); + $x = $x->bsqrt; + ok ($x, 1); + } diff --git a/lib/Math/BigInt/t/sub_mbf.t b/lib/Math/BigInt/t/sub_mbf.t index 6d64cf7..11f63dd 100755 --- a/lib/Math/BigInt/t/sub_mbf.t +++ b/lib/Math/BigInt/t/sub_mbf.t @@ -26,7 +26,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 2292 + plan tests => 2308 + 6; # + our own tests } diff --git a/lib/Math/BigInt/t/sub_mbi.t b/lib/Math/BigInt/t/sub_mbi.t index ea38bff..7a6b1e2 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 => 3257 + plan tests => 3273 + 5; # +5 own tests } diff --git a/lib/Math/BigInt/t/with_sub.t b/lib/Math/BigInt/t/with_sub.t index 3e829b1..878fe07 100644 --- a/lib/Math/BigInt/t/with_sub.t +++ b/lib/Math/BigInt/t/with_sub.t @@ -28,7 +28,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 2292 + plan tests => 2308 + 1; }