Upgrade to Math::BigInt 1.75, by Tels
Rafael Garcia-Suarez [Sun, 20 Mar 2005 21:20:50 +0000 (21:20 +0000)]
p4raw-id: //depot/perl@24048

lib/Math/BigFloat.pm
lib/Math/BigInt.pm
lib/Math/BigInt/Calc.pm
lib/Math/BigInt/t/bare_mbi.t
lib/Math/BigInt/t/bigintpm.inc
lib/Math/BigInt/t/bigintpm.t
lib/Math/BigInt/t/fallback.t
lib/Math/BigInt/t/mbi_rand.t
lib/Math/BigInt/t/sub_mbi.t

index 7466472..8143175 100644 (file)
@@ -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<scale>:
 
        $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<any> newly created number will be subject
+to the global rounding. This means that in the examples above, the C<3>
+as argument to C<bdiv()> 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
 
index f7ff612..1d31534 100644 (file)
@@ -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
index 39a0435..eb5ba98 100644 (file)
@@ -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
index bf08a90..b171e93 100644 (file)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 3012;
+  plan tests => 3014;
   }
 
 use Math::BigInt lib => 'BareCalc';
index 2a2bfe1..82d0cb2 100644 (file)
@@ -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
index 16f4d32..9923256 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 => 3012;
+  plan tests => 3014;
   }
 
 use Math::BigInt;
index e348d92..00f1dfd 100644 (file)
@@ -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));
 
index dd28051..d24920f 100644 (file)
@@ -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);
   }
index 4d4fc4e..9346dcd 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 3012
+  plan tests => 3014
     + 5;       # +5 own tests
   }