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 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))
# digits by default.
# Also used for default sqrt scale
$div_scale = 40;
# Rounding modes one of 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'.
$rnd_mode = 'even';
# bigfloat routines
#
# fadd(NSTR, NSTR) return NSTR addition
# fsub(NSTR, NSTR) return NSTR subtraction
# fmul(NSTR, NSTR) return NSTR multiplication
# fdiv(NSTR, NSTR[,SCALE]) returns NSTR division to SCALE places
# fneg(NSTR) return NSTR negation
# fabs(NSTR) return NSTR absolute value
# fcmp(NSTR,NSTR) return CODE compare undef,<0,=0,>0
# fround(NSTR, SCALE) return NSTR round to SCALE digits
# ffround(NSTR, SCALE) return NSTR round at SCALEth place
# fnorm(NSTR) return (NSTR) normalize
# fsqrt(NSTR[, SCALE]) return NSTR sqrt to SCALE places
# Convert a number to canonical string form.
# Takes something that looks like a number and converts it to
# the form /^[+-]\d+E[+-]\d+$/.
local($_) = @_;
s/\s+//g; # strip white space
if (/^([+-]?)(\d*)(\.(\d*))?([Ee]([+-]?\d+))?$/
&& ($2 ne '' || defined($4))) {
my $x = defined($4) ? $4 : '';
} else {
'NaN';
}
}
# normalize number -- for internal use
local($_, $exp) = @_;
if ($_ eq 'NaN') {
'NaN';
} else {
s/^([+-])0+/$1/; # strip leading zeros
if (length($_) == 1) {
'+0E+0';
} else {
sprintf("%sE%+ld", $_, $exp);
}
}
}
# negation
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
local($_) = &'fnorm($_[$[]);
s/^-/+/; # mash sign
$_;
}
# multiplication
if ($x eq 'NaN' || $y eq 'NaN') {
'NaN';
} else {
&norm(&'bmul($xm,$ym),$xe+$ye);
}
}
# addition
if ($x eq 'NaN' || $y eq 'NaN') {
'NaN';
} else {
}
}
# subtraction
}
# division
# args are dividend, divisor, scale (optional)
# result has at most max(scale, length(dividend), length(divisor)) digits
{
if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') {
'NaN';
} else {
}
}
# round int $q based on fraction $r/$base using $rnd_mode
local($q,$r,$base) = @_;
if ($q eq 'NaN' || $r eq 'NaN') {
'NaN';
} elsif ($rnd_mode eq 'trunc') {
$q; # just truncate
} else {
if ( $cmp < 0 ||
($cmp == 0 &&
( $rnd_mode eq 'zero' ||
$q; # round down
} else {
&'badd($q, ((substr($q,$[,1) eq '-') ? '-1' : '+1'));
# round up
}
}
}
# round the mantissa of $x to $scale digits
local($x,$scale) = (&'fnorm($_[$[]),$_[$[+1]);
$x;
} else {
$x;
} else {
}
}
}
# round $x at the 10 to the $scale digit place
local($x,$scale) = (&'fnorm($_[$[]),$_[$[+1]);
if ($x eq 'NaN') {
'NaN';
} else {
$x;
} else {
if ($xe < 1) {
'+0E+0';
} elsif ($xe == 1) {
# 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.
} else {
}
}
}
}
# compare 2 values returns one of undef, <0, =0, >0
# returns undef if either or both input value are not numbers
{
if ($x eq "NaN" || $y eq "NaN") {
undef;
} else {
ord($y) <=> ord($x)
||
|| &bigint'cmp($xm,$ym))
);
}
}
# square root by Newtons method.
local($x, $scale) = (&'fnorm($_[$[]), $_[$[+1]);
if ($x eq 'NaN' || $x =~ /^-/) {
'NaN';
} elsif ($x eq '+0E+0') {
'+0E+0';
} else {
$gs *= 2;
}
&'fround($guess, $scale);
}
}
1;