X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2Fbigfloat.pl;h=8c28abdcd1d2eb4e0090e3d6718e5676f59c14f6;hb=bc0bedcc9a054d550e68cd3ebd606b073b4151f7;hp=52fb7e38805828b59437607e80898d20bcc8c9b5;hpb=68decaef0a08fcd5db3193f825cfdfc539b67ccb;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/bigfloat.pl b/lib/bigfloat.pl index 52fb7e3..8c28abd 100644 --- a/lib/bigfloat.pl +++ b/lib/bigfloat.pl @@ -1,17 +1,26 @@ package bigfloat; require "bigint.pl"; +# +# This library is no longer being maintained, and is included for backward +# compatibility with Perl 4 programs which may require it. +# +# In particular, this should not be used as an example of modern Perl +# programming techniques. +# +# Suggested alternative: Math::BigFloat +# # Arbitrary length float math package # # by Mark Biggar # # number format # canonical strings have the form /[+-]\d+E[+-]\d+/ -# Input values can have inbedded whitespace +# Input values can have embedded whitespace # Error returns # 'NaN' An input parameter was "Not a Number" or # divide by zero or sqrt of negative number # Division is computed to -# max($div_scale,length(dividend).length(divisor)) +# max($div_scale,length(dividend)+length(divisor)) # digits by default. # Also used for default sqrt scale @@ -41,8 +50,10 @@ $rnd_mode = 'even'; sub main'fnorm { #(string) return fnum_str local($_) = @_; s/\s+//g; # strip white space - if (/^([+-]?)(\d*)(\.(\d*))?([Ee]([+-]?\d+))?$/ && "$2$4" ne '') { - &norm(($1 ? "$1$2$4" : "+$2$4"),(($4 ne '') ? $6-length($4) : $6)); + if (/^([+-]?)(\d*)(\.(\d*))?([Ee]([+-]?\d+))?$/ + && ($2 ne '' || defined($4))) { + my $x = defined($4) ? $4 : ''; + &norm(($1 ? "$1$2$x" : "+$2$x"), (($x ne '') ? $6-length($x) : $6)); } else { 'NaN'; } @@ -66,22 +77,27 @@ sub norm { #(mantissa, exponent) return fnum_str # negation sub main'fneg { #(fnum_str) return fnum_str - local($_) = &'fnorm($_[0]); - vec($_,0,8) =^ ord('+') ^ ord('-') unless $_ eq '+0E+0'; # flip sign - s/^H/N/; + local($_) = &'fnorm($_[$[]); + vec($_,0,8) ^= ord('+') ^ ord('-') unless $_ eq '+0E+0'; # flip sign + if ( ord("\t") == 9 ) { # ascii + s/^H/N/; + } + else { # ebcdic character set + s/\373/N/; + } $_; } # absolute value sub main'fabs { #(fnum_str) return fnum_str - local($_) = &'fnorm($_[0]); + local($_) = &'fnorm($_[$[]); s/^-/+/; # mash sign $_; } # multiplication sub main'fmul { #(fnum_str, fnum_str) return fnum_str - local($x,$y) = (&'fnorm($_[0]),&'fnorm($_[1])); + local($x,$y) = (&'fnorm($_[$[]),&'fnorm($_[$[+1])); if ($x eq 'NaN' || $y eq 'NaN') { 'NaN'; } else { @@ -93,7 +109,7 @@ sub main'fmul { #(fnum_str, fnum_str) return fnum_str # addition sub main'fadd { #(fnum_str, fnum_str) return fnum_str - local($x,$y) = (&'fnorm($_[0]),&'fnorm($_[1])); + local($x,$y) = (&'fnorm($_[$[]),&'fnorm($_[$[+1])); if ($x eq 'NaN' || $y eq 'NaN') { 'NaN'; } else { @@ -106,7 +122,7 @@ sub main'fadd { #(fnum_str, fnum_str) return fnum_str # subtraction sub main'fsub { #(fnum_str, fnum_str) return fnum_str - &'fadd($_[0],&'fneg($_[1])); + &'fadd($_[$[],&'fneg($_[$[+1])); } # division @@ -114,7 +130,7 @@ sub main'fsub { #(fnum_str, fnum_str) return fnum_str # result has at most max(scale, length(dividend), length(divisor)) digits sub main'fdiv #(fnum_str, fnum_str[,scale]) return fnum_str { - local($x,$y,$scale) = (&'fnorm($_[0]),&'fnorm($_[1]),$_[2]); + local($x,$y,$scale) = (&'fnorm($_[$[]),&'fnorm($_[$[+1]),$_[$[+2]); if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') { 'NaN'; } else { @@ -124,7 +140,7 @@ sub main'fdiv #(fnum_str, fnum_str[,scale]) return fnum_str $scale = length($xm)-1 if (length($xm)-1 > $scale); $scale = length($ym)-1 if (length($ym)-1 > $scale); $scale = $scale + length($ym) - length($xm); - &norm(&round(&'bdiv($xm.('0' x $scale),$ym),$ym), + &norm(&round(&'bdiv($xm.('0' x $scale),$ym),&'babs($ym)), $xe-$ye-$scale); } } @@ -141,13 +157,13 @@ sub round { #(int_str, int_str, int_str) return int_str if ( $cmp < 0 || ($cmp == 0 && ( $rnd_mode eq 'zero' || - ($rnd_mode eq '-inf' && (substr($q,0,1) eq '+')) || - ($rnd_mode eq '+inf' && (substr($q,0,1) eq '-')) || + ($rnd_mode eq '-inf' && (substr($q,$[,1) eq '+')) || + ($rnd_mode eq '+inf' && (substr($q,$[,1) eq '-')) || ($rnd_mode eq 'even' && $q =~ /[24680]$/) || ($rnd_mode eq 'odd' && $q =~ /[13579]$/) )) ) { $q; # round down } else { - &'badd($q, ((substr($q,0,1) eq '-') ? '-1' : '+1')); + &'badd($q, ((substr($q,$[,1) eq '-') ? '-1' : '+1')); # round up } } @@ -155,7 +171,7 @@ sub round { #(int_str, int_str, int_str) return int_str # round the mantissa of $x to $scale digits sub main'fround { #(fnum_str, scale) return fnum_str - local($x,$scale) = (&'fnorm($_[0]),$_[1]); + local($x,$scale) = (&'fnorm($_[$[]),$_[$[+1]); if ($x eq 'NaN' || $scale <= 0) { $x; } else { @@ -163,8 +179,8 @@ sub main'fround { #(fnum_str, scale) return fnum_str if (length($xm)-1 <= $scale) { $x; } else { - &norm(&round(substr($xm,0,$scale+1), - "+0".substr($xm,$scale+1,1),"+10"), + &norm(&round(substr($xm,$[,$scale+1), + "+0".substr($xm,$[+$scale+1,1),"+10"), $xe+length($xm)-$scale-1); } } @@ -172,7 +188,7 @@ sub main'fround { #(fnum_str, scale) return fnum_str # round $x at the 10 to the $scale digit place sub main'ffround { #(fnum_str, scale) return fnum_str - local($x,$scale) = (&'fnorm($_[0]),$_[1]); + local($x,$scale) = (&'fnorm($_[$[]),$_[$[+1]); if ($x eq 'NaN') { 'NaN'; } else { @@ -184,10 +200,15 @@ sub main'ffround { #(fnum_str, scale) return fnum_str if ($xe < 1) { '+0E+0'; } elsif ($xe == 1) { - &norm(&round('+0',"+0".substr($xm,1,1),"+10"), $scale); + # The first substr preserves the sign, which means that + # we'll pass a non-normalized "-0" to &round when rounding + # -0.006 (for example), purely so that &round won't lose + # the sign. + &norm(&round(substr($xm,$[,1).'0', + "+0".substr($xm,$[+1,1),"+10"), $scale); } else { - &norm(&round(substr($xm,0,$trunc), - "+0".substr($xm,$trunc,1),"+10"), $scale); + &norm(&round(substr($xm,$[,$xe), + "+0".substr($xm,$[+$xe,1),"+10"), $scale); } } } @@ -197,14 +218,14 @@ sub main'ffround { #(fnum_str, scale) return fnum_str # returns undef if either or both input value are not numbers sub main'fcmp #(fnum_str, fnum_str) return cond_code { - local($x, $y) = (&'fnorm($_[0]),&'fnorm($_[1])); + local($x, $y) = (&'fnorm($_[$[]),&'fnorm($_[$[+1])); if ($x eq "NaN" || $y eq "NaN") { undef; } else { ord($y) <=> ord($x) || ( local($xm,$xe,$ym,$ye) = split('E', $x."E$y"), - (($xe <=> $ye) * (substr($x,0,1).'1') + (($xe <=> $ye) * (substr($x,$[,1).'1') || &bigint'cmp($xm,$ym)) ); } @@ -212,7 +233,7 @@ sub main'fcmp #(fnum_str, fnum_str) return cond_code # square root by Newtons method. sub main'fsqrt { #(fnum_str[, scale]) return fnum_str - local($x, $scale) = (&'fnorm($_[0]), $_[1]); + local($x, $scale) = (&'fnorm($_[$[]), $_[$[+1]); if ($x eq 'NaN' || $x =~ /^-/) { 'NaN'; } elsif ($x eq '+0E+0') {