From: Jarkko Hietaniemi Date: Fri, 6 Apr 2001 13:54:52 +0000 (+0000) Subject: Math::BigFloat patches from John Peacock. The equivalent X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=288d023a84099384e11cf3c2fe39903b18188b9d;p=p5sagit%2Fp5-mst-13.2.git Math::BigFloat patches from John Peacock. The equivalent of #9586 from maintperl but reworked by John to work with the bleadperl. p4raw-id: //depot/perl@9590 --- diff --git a/lib/Math/BigFloat.pm b/lib/Math/BigFloat.pm index 4c520fd..ff8aea5 100644 --- a/lib/Math/BigFloat.pm +++ b/lib/Math/BigFloat.pm @@ -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 digits by default. @@ -392,5 +422,5 @@ as follows: =head1 AUTHOR Mark Biggar - +Patches by John Peacock Apr 2001 =cut diff --git a/t/lib/bigfltpm.t b/t/lib/bigfltpm.t index a9725ba..18bab4f 100755 --- a/t/lib/bigfltpm.t +++ b/t/lib/bigfltpm.t @@ -9,9 +9,9 @@ use Math::BigFloat; $test = 0; $| = 1; -print "1..406\n"; +print "1..414\n"; while () { - chop; + chomp; if (s/^&//) { $f = $_; } elsif (/^\$.*/) { @@ -53,6 +53,8 @@ while () { $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 () { 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 () { __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.