Upgrade to Math::BigInt v1.89
authorRafael Garcia-Suarez <rgarciasuarez@gmail.com>
Mon, 21 Apr 2008 07:34:12 +0000 (07:34 +0000)
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>
Mon, 21 Apr 2008 07:34:12 +0000 (07:34 +0000)
p4raw-id: //depot/perl@33715

15 files changed:
lib/Math/BigFloat.pm
lib/Math/BigInt.pm
lib/Math/BigInt/t/bare_mbf.t
lib/Math/BigInt/t/bare_mbi.t
lib/Math/BigInt/t/bigfltpm.inc
lib/Math/BigInt/t/bigfltpm.t
lib/Math/BigInt/t/bigintpm.inc
lib/Math/BigInt/t/bigintpm.t
lib/Math/BigInt/t/calling.t
lib/Math/BigInt/t/const_mbf.t
lib/Math/BigInt/t/constant.t
lib/Math/BigInt/t/mbimbf.t
lib/Math/BigInt/t/sub_mbf.t
lib/Math/BigInt/t/sub_mbi.t
lib/Math/BigInt/t/with_sub.t

index 6e1ecc8..27d60b3 100644 (file)
@@ -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<Note>: 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:
index 362769f..b19b3dc 100644 (file)
@@ -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<MATH LIBRARY> 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<Math::BigInt::Calc>. 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<Note>: 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<much> faster), and there is
-no penalty if Math::BigInt::GMP is not installed, it is a good idea to always
-use the following:
+B<Note>: 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<Math::BigInt::GMP> and L<Math::BigInt::Pari> 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<NOT> 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<NOT> 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<MATH LIBRARY> for more information.
+You can use an alternative library to drive Math::BigInt. See the section
+L<MATH LIBRARY> for more information.
 
 For more benchmark results see L<http://bloodgate.com/perl/benchmarks.html>.
 
index 53b9fb4..9bb4bce 100644 (file)
@@ -27,7 +27,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2292;
+  plan tests => 2308;
   }
 
 use Math::BigFloat lib => 'BareCalc';
index 6b572ee..637e695 100644 (file)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 3257;
+  plan tests => 3273;
   }
 
 use Math::BigInt lib => 'BareCalc';
index 10cfaf0..7d650e5 100644 (file)
@@ -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
index 0956883..a41996e 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2292
+  plan tests => 2308
        + 5;            # own tests
   }
 
index 53c6629..87140ba 100644 (file)
@@ -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
index 9442fbb..b4f5bf2 100755 (executable)
@@ -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';
index 3fee915..4789cc7 100644 (file)
@@ -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;
index be86407..a73177e 100644 (file)
@@ -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';
index 8df7283..3e69bae 100644 (file)
@@ -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';
index fae3c8c..1ac9ada 100644 (file)
@@ -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);
+  }
index 6d64cf7..11f63dd 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n"; 
   
-  plan tests => 2292
+  plan tests => 2308
     + 6;       # + our own tests
   }
 
index ea38bff..7a6b1e2 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 3257
+  plan tests => 3273
     + 5;       # +5 own tests
   }
 
index 3e829b1..878fe07 100644 (file)
@@ -28,7 +28,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2292
+  plan tests => 2308
        + 1;
   }