This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Math::BigInt v1.67 released
authorTels <nospam-abuse@bloodgate.com>
Fri, 12 Dec 2003 18:47:43 +0000 (19:47 +0100)
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>
Fri, 12 Dec 2003 22:43:11 +0000 (22:43 +0000)
Message-Id: <200312121847.49039@bloodgate.com>

p4raw-id: //depot/perl@21882

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/downgrade.t
lib/Math/BigInt/t/fallback.t
lib/Math/BigInt/t/sub_mbi.t

index dfb2671..3b8d5a6 100644 (file)
@@ -172,8 +172,9 @@ sub new
     # undef,undef to signal MBI that we don't need no bloody rounding
     $self->{_e} = $MBI->new("$$es$$ev",undef,undef);   # exponent
     $self->{_m} = $MBI->new("$$miv$$mfv",undef,undef);         # create mant.
+    # print  $self->{_e}, " ", $self->{_m},"\n";
     # 3.123E0 = 3123E-3, and 3.123E-2 => 3123E-5
-    $self->{_e} -= CORE::length($$mfv) if CORE::length($$mfv) != 0;            
+    $self->{_e} -= CORE::length($$mfv) if CORE::length($$mfv) != 0;
     $self->{sign} = $$mis;
     }
   # if downgrade, inf, NaN or integers go down
@@ -186,7 +187,7 @@ sub new
       $self->{_m}->{sign} = $$mis;             # negative if wanted
       return $downgrade->new($self->{_m});
       }
-    return $downgrade->new("$$mis$$miv$$mfv"."E$$es$$ev");
+    return $downgrade->new($self->bsstr()); 
     }
   #print "mbf new $self->{sign} $self->{_m} e $self->{_e} ",ref($self),"\n";
   $self->bnorm()->round(@r);                   # first normalize, then round
index 0e4ae68..1b16600 100644 (file)
@@ -1250,7 +1250,7 @@ sub blog
 
   if ($CAN{log_int})
     {
-    my $rc = $CALC->_log_int($x->{value},$base->{value});
+    my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value});
     return $x->bnan() unless defined $rc;
     $x->{value} = $rc;
     return $x->round(@r);
@@ -3093,7 +3093,7 @@ sub _split
     # valid mantissa?
     return if $m eq '.' || $m eq '';
     my ($mi,$mf,$lastf) = split /\./,$m;
-    return if defined $lastf;          # last defined => 1.2.3 or others
+    return if defined $lastf;          # lastf defined => 1.2.3 or others
     $mi = '0' if !defined $mi;
     $mi .= '0' if $mi =~ /^[\-\+]?$/;
     $mf = '0' if !defined $mf || $mf eq '';
index 6db1a62..02770e2 100644 (file)
@@ -1351,38 +1351,48 @@ sub _log_int
   if ($cmp == 0)
     {
     splice (@$x,1); $x->[0] = 1;
-    return $x;
+    return ($x,1)
     }
   # X < BASE
   if ($cmp < 0)
     {
     splice (@$x,1); $x->[0] = 0;
-    return $x;
+    return ($x,undef);
     }
 
   # this trial multiplication is very fast, even for large counts (like for
   # 2 ** 1024, since this still requires only 1024 very fast steps
   # (multiplication of a large number by a very small number is very fast))
   my $x_org = _copy($c,$x);            # preserve x
-  splice(@$x,1); $x->[0] = 0;          # keep ref to $x
+  splice(@$x,1); $x->[0] = 1;          # keep ref to $x
+
+  # simple loop that increments $x by two in each step, possible overstepping
+  # the real result by one
 
   # use a loop that keeps $x as scalar as long as possible (this is faster)
-  my $trial = _copy($c,$base); my $count = 0; my $a;
-  while (($a = _acmp($x,$trial,$x_org) <= 0) && $count < $BASE)
+  my $trial = _copy($c,$base); my $a;
+  my $base_mul = _mul($c, _copy($c,$base), $base);
+
+  while (($a = _acmp($x,$trial,$x_org)) < 0)
     {
-    _mul($c,$trial,$base); $count++;
+    _mul($c,$trial,$base_mul); _add($c, $x, [2]);
     }
-  if ($a <= 0)
+
+  my $exact = 1;
+  if ($a > 0)
     {
-    # not done yet?
-    $x->[0] = $count;
-    while (_acmp($x,$trial,$x_org) <= 0)
+    # overstepped the result
+    _dec($c, $x);
+    _div($c,$trial,$base);
+    $a = _acmp($x,$trial,$x_org);
+    if ($a > 0)
       {
-      _mul($c,$trial,$base); _inc($c,$x);
+      _dec($c, $x);
       }
+    $exact = 0 if $a != 0;
     }
   
-  $x;                          # return result
+  ($x,$exact);                         # return result
   }
 
 # for debugging:
@@ -1978,6 +1988,10 @@ slow) fallback routines to emulate these:
        _modpow         return modulus of power ($x ** $y) % $z
        _log_int(X,N)   calculate integer log() of X in base N
                        X >= 0, N >= 0 (return undef for NaN)
+                       returns (RESULT, EXACT) where EXACT is:
+                        1     : result is exactly RESULT
+                        0     : result was truncated to RESULT
+                        undef : unknown whether result is exactly RESULT
 
 Input strings come in as unsigned but with prefix (i.e. as '123', '0xabc'
 or '0b1101').
index 6bcc6bd..0af4c42 100644 (file)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2728;
+  plan tests => 2760;
   }
 
 use Math::BigInt lib => 'BareCalc';
index 332f575..db52553 100644 (file)
@@ -718,6 +718,22 @@ inf:inf:NaN
 15625:5:6
 15626:5:6
 15624:5:5
+1000:10:3
+10000:10:4
+100000:10:5
+1000000:10:6
+10000000:10:7
+100000000:10:8
+8916100448256:12:12
+8916100448257:12:12
+8916100448255:12:11
+2251799813685248:8:17
+72057594037927936:2:56
+144115188075855872:2:57
+288230376151711744:2:58
+576460752303423488:2:59
+4096:2:12
+1329227995784915872903807060280344576:2:120
 # $x == $base => result 1
 3:3:1
 # $x < $base => result 0 ($base ** 0 <= $x)
index b541aae..d4e0772 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 => 2728;
+  plan tests => 2760;
   }
 
 use Math::BigInt;
index 0208a56..25d672c 100644 (file)
@@ -10,7 +10,7 @@ BEGIN
   my $location = $0; $location =~ s/downgrade.t//;
   unshift @INC, $location; # to locate the testing files
   chdir 't' if -d 't';
-  plan tests => 12;
+  plan tests => 15;
   }
 
 use Math::BigInt upgrade => 'Math::BigFloat';
@@ -36,6 +36,12 @@ ok (ref(Math::BigFloat->new('10')),'Math::BigInt');
 ok (ref(Math::BigFloat->new('-10')),'Math::BigInt');
 ok (ref(Math::BigFloat->new('-10.0E1')),'Math::BigInt');
 
+# bug until v1.67:
+ok (Math::BigFloat->new('0.2E0'), '0.2');
+ok (Math::BigFloat->new('0.2E1'), '2');
+# until v1.67 resulted in 200:
+ok (Math::BigFloat->new('0.2E2'), '20');
+
 # disable, otherwise it screws calculations
 Math::BigFloat->upgrade(undef);
 ok (Math::BigFloat->upgrade()||'','');
index c09a201..e348d92 100644 (file)
@@ -31,6 +31,10 @@ BEGIN
   plan tests => 8;
   }
 
+# 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)
+# should calculate the result to X digits accuracy. For now, this is better
+# than die()ing...
 
 use Math::BigInt;
 use Math::BigFloat;
index 65c6d0b..3b3c6e6 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2728
+  plan tests => 2760
     + 5;       # +5 own tests
   }