Math::BigFloat patches from John Peacock. The equivalent
Jarkko Hietaniemi [Fri, 6 Apr 2001 13:54:52 +0000 (13:54 +0000)]
of #9586 from maintperl but reworked by John to work with
the bleadperl.

p4raw-id: //depot/perl@9590

lib/Math/BigFloat.pm
t/lib/bigfltpm.t

index 4c520fd..ff8aea5 100644 (file)
@@ -4,7 +4,7 @@ use Math::BigInt;
 
 use Exporter;  # just for use to be happy
 @ISA = (Exporter);
-$VERSION = '0.01';     # never had version before
+$VERSION = '0.03';
 
 use overload
 '+'    =>      sub {new Math::BigFloat &fadd},
@@ -13,9 +13,12 @@ use overload
 '<=>'  =>      sub {$_[2]? fcmp($_[1],${$_[0]}) : fcmp(${$_[0]},$_[1])},
 'cmp'  =>      sub {$_[2]? ($_[1] cmp ${$_[0]}) : (${$_[0]} cmp $_[1])},
 '*'    =>      sub {new Math::BigFloat &fmul},
-'/'    =>      sub {new Math::BigFloat 
+'/'    =>      sub {new Math::BigFloat
                       $_[2]? scalar fdiv($_[1],${$_[0]}) :
                         scalar fdiv(${$_[0]},$_[1])},
+'%'    =>      sub {new Math::BigFloat
+                      $_[2]? scalar fmod($_[1],${$_[0]}) :
+                        scalar fmod(${$_[0]},$_[1])},
 'neg'  =>      sub {new Math::BigFloat &fneg},
 'abs'  =>      sub {new Math::BigFloat &fabs},
 'int'  =>      sub {new Math::BigInt &f2int},
@@ -45,12 +48,15 @@ sub stringify {
     my $e = $1;
     my $ln = length($n);
 
-    if ($e > 0) {
-       $n .= "0" x $e . '.';
-    } elsif (abs($e) < $ln) {
-       substr($n, $ln + $e, 0) = '.';
-    } else {
-       $n = '.' . ("0" x (abs($e) - $ln)) . $n;
+    if ( defined $e )
+    {
+        if ($e > 0) {
+        $n .= "0" x $e . '.';
+        } elsif (abs($e) < $ln) {
+        substr($n, $ln + $e, 0) = '.';
+        } else {
+        $n = '.' . ("0" x (abs($e) - $ln)) . $n;
+        }
     }
     $n = "-$n" if $minus;
 
@@ -150,7 +156,7 @@ sub fadd { #(fnum_str, fnum_str) return fnum_str
 
 # subtraction
 sub fsub { #(fnum_str, fnum_str) return fnum_str
-    fadd($_[$[],fneg($_[$[+1]));    
+    fadd($_[$[],fneg($_[$[+1]));
 }
 
 # division
@@ -174,6 +180,27 @@ sub fdiv #(fnum_str, fnum_str[,scale]) return fnum_str
     }
 }
 
+# modular division
+#   args are dividend, divisor
+sub fmod #(fnum_str, fnum_str) return fnum_str
+{
+    local($x,$y) = (fnorm($_[$[]),fnorm($_[$[+1]));
+    if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') {
+       'NaN';
+    } else {
+       local($xm,$xe) = split('E',$x);
+       local($ym,$ye) = split('E',$y);
+       if ( $xe < $ye )
+       {
+               $ym .= ('0' x ($ye-$xe));
+       }
+       else
+       {
+               $xm .= ('0' x ($xe-$ye));
+       }
+       &norm(Math::BigInt::bmod($xm,$ym));
+    }
+}
 # round int $q based on fraction $r/$base using $rnd_mode
 sub round { #(int_str, int_str, int_str) return int_str
     local($q,$r,$base) = @_;
@@ -188,9 +215,9 @@ sub round { #(int_str, int_str, int_str) return int_str
                   ($rnd_mode eq 'zero'                            ) ||
                   ($rnd_mode eq '-inf' && (substr($q,$[,1) eq '+')) ||
                   ($rnd_mode eq '+inf' && (substr($q,$[,1) eq '-')) ||
-                  ($rnd_mode eq 'even' && $q =~ /[13579]$/        ) ||
-                  ($rnd_mode eq 'odd'  && $q =~ /[24680]$/        )    )
-                 ) 
+                  ($rnd_mode eq 'even' && $q =~ /[24680]$/        ) ||
+                  ($rnd_mode eq 'odd'  && $q =~ /[13579]$/        )    )
+                 )
                ) {
            $q;                     # round down
        } else {
@@ -210,8 +237,8 @@ sub fround { #(fnum_str, scale) return fnum_str
        if (length($xm)-1 <= $scale) {
            $x;
        } else {
-           &norm(&round(substr($xm,$[,$scale+1),
-                        "+0".substr($xm,$[+$scale+1,1),"+10"),
+               &norm(&round(substr($xm,$[,$scale+1),
+                        "+0".substr($xm,$[+$scale+1),"+1"."0" x length(substr($xm,$[+$scale+1))),
                  $xe+length($xm)-$scale-1);
        }
     }
@@ -235,10 +262,12 @@ sub ffround { #(fnum_str, scale) return fnum_str
                # normalized "-0" to &round when rounding -0.006 (for
                # example), purely so &round won't lose the sign.
                &norm(&round(substr($xm,$[,1).'0',
-                     "+0".substr($xm,$[+1,1),"+10"), $scale);
+                     "+0".substr($xm,$[+1),
+                     "+1"."0" x length(substr($xm,$[+1))), $scale);
            } else {
                &norm(&round(substr($xm,$[,$xe),
-                     "+0".substr($xm,$[+$xe,1),"+10"), $scale);
+                     "+0".substr($xm,$[+$xe),
+                     "+1"."0" x length(substr($xm,$[+$xe))), $scale);
            }
        }
     }
@@ -263,7 +292,7 @@ sub f2int { #(fnum_str) return inum_str
        }
     }
 }
-    
+
 # compare 2 values returns one of undef, <0, =0, >0
 #   returns undef if either or both input value are not numbers
 sub fcmp #(fnum_str, fnum_str) return cond_code
@@ -326,6 +355,7 @@ Math::BigFloat - Arbitrary length float math package
   $f->fsub(NSTR) return NSTR            subtraction
   $f->fmul(NSTR) return NSTR            multiplication
   $f->fdiv(NSTR[,SCALE]) returns NSTR   division to SCALE places
+  $f->fmod(NSTR) returns NSTR           modular remainder
   $f->fneg() return NSTR                negation
   $f->fabs() return NSTR                absolute value
   $f->fcmp(NSTR) return CODE            compare undef,<0,=0,>0
@@ -353,7 +383,7 @@ have embedded whitespace.
 An input parameter was "Not a Number" or divide by zero or sqrt of
 negative number.
 
-=item Division is computed to 
+=item Division is computed to
 
 C<max($Math::BigFloat::div_scale,length(dividend)+length(divisor))>
 digits by default.
@@ -392,5 +422,5 @@ as follows:
 =head1 AUTHOR
 
 Mark Biggar
-
+Patches by John Peacock Apr 2001
 =cut
index a9725ba..18bab4f 100755 (executable)
@@ -9,9 +9,9 @@ use Math::BigFloat;
 
 $test = 0;
 $| = 1;
-print "1..406\n";
+print "1..414\n";
 while (<DATA>) {
-       chop;
+       chomp;
        if (s/^&//) {
                $f = $_;
        } elsif (/^\$.*/) {
@@ -53,6 +53,8 @@ while (<DATA>) {
                        $try .= "\$x * \$y;";
                    } elsif ($f eq "fdiv") {
                        $try .= "\$x / \$y;";
+                   } elsif ($f eq "fmod") {
+                       $try .= "\$x % \$y;";
                    } else { warn "Unknown op"; }
                }
                #print ">>>",$try,"<<<\n";
@@ -67,14 +69,18 @@ while (<DATA>) {
                        print "# '$try' expected: /$pat/ got: '$ans1'\n";
                   }
               }
-               elsif ("$ans1" eq $ans) { #bug!
-                       print "ok $test\n";
-               } else {
-                       print "not ok $test\n";
-                       print "# '$try' expected: '$ans' got: '$ans1'\n";
-               }
+                else {
+
+                       $ans1_str = defined $ans1? "$ans1" : "";
+                       if ($ans1_str eq $ans) { #bug!
+                              print "ok $test\n";
+                      } else {
+                              print "not ok $test\n";
+                              print "# '$try' expected: '$ans' got: '$ans1'\n";
+                      }
+              }
        }
-} 
+}
 
 {
   use Math::BigFloat ':constant';
@@ -96,12 +102,12 @@ while (<DATA>) {
 
 __END__
 &fnorm
-abc:NaN.
-   1 a:NaN.
-1bcd2:NaN.
-11111b:NaN.
-+1z:NaN.
--1z:NaN.
+abc:NaN
+   1 a:NaN
+1bcd2:NaN
+11111b:NaN
++1z:NaN
+-1z:NaN
 0:0.
 +0:0.
 +00:0.
@@ -119,7 +125,7 @@ abc:NaN.
 -001:-1.
 -123456789:-123456789.
 -00000100000:-100000.
-123.456a:NaN.
+123.456a:NaN
 123.456:123.456
 0.01:.01
 .002:.002
@@ -134,7 +140,7 @@ abc:NaN.
 -3e111:-3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
 -4e-1111:-.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004
 &fneg
-abd:NaN.
+abc:NaN
 +0:0.
 +1:-1.
 -1:1.
@@ -143,7 +149,7 @@ abd:NaN.
 +123.456789:-123.456789
 -123456.789:123456.789
 &fabs
-abc:NaN.
+abc:NaN
 +0:0.
 +1:1.
 -1:1.
@@ -185,15 +191,15 @@ $Math::BigFloat::rnd_mode = 'odd'
 -50123456789:5:-50123000000
 +50123456789:9:50123456800
 -50123456789:9:-50123456800
-+501234500:6:501234000
--501234500:6:-501234000
++501234500:6:501235000
+-501234500:6:-501235000
 $Math::BigFloat::rnd_mode = 'even'
 +60123456789:5:60123000000
 -60123456789:5:-60123000000
 +60123456789:9:60123456800
 -60123456789:9:-60123456800
-+601234500:6:601235000
--601234500:6:-601235000
++601234500:6:601234000
+-601234500:6:-601234000
 &ffround
 $Math::BigFloat::rnd_mode = 'trunc'
 +1.23:-1:1.2
@@ -256,13 +262,13 @@ $Math::BigFloat::rnd_mode = 'odd'
 -5.23:-1:/-5.2(?:0{5}\d+)?
 +5.27:-1:/5.(?:3|29{5}\d+)
 -5.27:-1:/-5.(?:3|29{5}\d+)
-+5.25:-1:/5.(?:2|29{5}\d+)
--5.25:-1:/-5.(?:2|29{5}\d+)
-+5.35:-1:/5.(?:4|29{5}\d+)
--5.35:-1:/-5.(?:4|29{5}\d+)
++5.25:-1:/5.(?:3|29{5}\d+)
+-5.25:-1:/-5.(?:3|29{5}\d+)
++5.35:-1:/5.(?:3|29{5}\d+)
+-5.35:-1:/-5.(?:3|29{5}\d+)
 -0.0065:-1:0
 -0.0065:-2:/-0\.01|-1e-02
--0.0065:-3:/-0\.006|-6e-03
+-0.0065:-3:/-0\.007|-7e-03
 -0.0065:-4:/-0\.006(?:5|49{5}\d+)|-6\.5e-03
 -0.0065:-5:/-0\.006(?:5|49{5}\d+)|-6\.5e-03
 $Math::BigFloat::rnd_mode = 'even'
@@ -270,13 +276,13 @@ $Math::BigFloat::rnd_mode = 'even'
 -6.23:-1:/-6.2(?:0{5}\d+)?
 +6.27:-1:/6.(?:3|29{5}\d+)
 -6.27:-1:/-6.(?:3|29{5}\d+)
-+6.25:-1:/6.(?:3(?:0{5}\d+)?|29{5}\d+)
--6.25:-1:/-6.(?:3(?:0{5}\d+)?|29{5}\d+)
-+6.35:-1:/6.(?:3|39{5}\d+|29{8}\d+)
--6.35:-1:/-6.(?:3|39{5}\d+|29{8}\d+)
++6.25:-1:/6.(?:2(?:0{5}\d+)?|29{5}\d+)
+-6.25:-1:/-6.(?:2(?:0{5}\d+)?|29{5}\d+)
++6.35:-1:/6.(?:4|39{5}\d+|29{8}\d+)
+-6.35:-1:/-6.(?:4|39{5}\d+|29{8}\d+)
 -0.0065:-1:0
 -0.0065:-2:/-0\.01|-1e-02
--0.0065:-3:/-0\.007|-7e-03
+-0.0065:-3:/-0\.006|-7e-03
 -0.0065:-4:/-0\.006(?:5|49{5}\d+)|-6\.5e-03
 -0.0065:-5:/-0\.006(?:5|49{5}\d+)|-6\.5e-03
 &fcmp
@@ -307,9 +313,9 @@ abc:+0:
 -123:-124:1
 -124:-123:-1
 &fadd
-abc:abc:NaN.
-abc:+0:NaN.
-+0:abc:NaN.
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
 +0:+0:0.
 +1:+0:1.
 +0:+1:1.
@@ -345,9 +351,9 @@ abc:+0:NaN.
 -123456789:-987654321:-1111111110.
 +123456789:-987654321:-864197532.
 &fsub
-abc:abc:NaN.
-abc:+0:NaN.
-+0:abc:NaN.
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
 +0:+0:0.
 +1:+0:1.
 +0:+1:-1.
@@ -383,9 +389,9 @@ abc:+0:NaN.
 -123456789:-987654321:864197532.
 +123456789:-987654321:1111111110.
 &fmul
-abc:abc:NaN.
-abc:+0:NaN.
-+0:abc:NaN.
+abc:abc:NaN
+abc:+0:NaN
++0:abc:NaN
 +0:+0:0.
 +0:+1:0.
 +1:+0:0.
@@ -416,14 +422,14 @@ abc:+0:NaN.
 +88888888888:+9:799999999992.
 +99999999999:+9:899999999991.
 &fdiv
-abc:abc:NaN.
-abc:+1:abc:NaN.
-+1:abc:NaN.
-+0:+0:NaN.
+abc:abc:NaN
+abc:+1:abc:NaN
++1:abc:NaN
++0:+0:NaN
 +0:+1:0.
-+1:+0:NaN.
++1:+0:NaN
 +0:-1:0.
--1:+0:NaN.
+-1:+0:NaN
 +1:+1:1.
 -1:-1:1.
 +1:-1:-1.
@@ -470,10 +476,10 @@ $Math::BigFloat::div_scale = 20
 $Math::BigFloat::div_scale = 40
 &fsqrt
 +0:0
--1:/^(?i:0|\?|-?N\.?aNQ?)$
--2:/^(?i:0|\?|-?N\.?aNQ?)$
--16:/^(?i:0|\?|-?N\.?aNQ?)$
--123.456:/^(?i:0|\?|-?N\.?aNQ?)$
+-1:/^(?i:0|\?|NaNQ?)$
+-2:/^(?i:0|\?|NaNQ?)$
+-16:/^(?i:0|\?|NaNQ?)$
+-123.456:/^(?i:0|\?|NaNQ?)$
 +1:1.
 +1.44:1.2
 +2:1.41421356237309504880168872420969807857
@@ -525,3 +531,12 @@ $Math::BigFloat::div_scale = 40
 -12345678901234567890E-20:+0
 -12345678901234567890E-21:+0
 -12345678901234567890E-225:+0
+&fmod
++0:0:NaN
++0:1:0.
++3:1:0.
++5:2:1.
++9:4:1.
++9:5:4.
++9000:56:40.
++56:9000:56.