home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
LIBRARY
/
FLTD.SA
< prev
next >
Wrap
Text File
|
1995-02-05
|
23KB
|
739 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
value class FLTD < $IS_EQ{FLTD}, $IS_LT{FLTD}, $NIL{FLTD} is
-- IEEE 754-1984 "double" format 64-bit floating point.
create(f:FLT):SAME is
-- For convenience in creating. Allows writing #FLTD(45.678).
return f.fltd
end;
create(f:SAME):SAME is
-- For convenience in creating. Allows writing #FLTD(45.678d).
return f;
end;
plus(f:SAME):SAME is -- The sum of self and `f'. Built-in.
raise "FLTD::plus(SAME):SAME undefined.";
end;
minus(f:SAME):SAME is -- The difference between self and `f'. Built-in.
raise "FLTD::minus(SAME):SAME undefined.";
end;
negate:SAME is
-- The negation of self. Same as zero minus self. (Well, almost,
-- except for IEEE rounding modes and the sign bit.)
raise "FLTD::negate:SAME undefined.";
end;
times(f:SAME):SAME is -- The signed product of self and `f'. Built-in.
raise "FLTD::times(SAME):SAME undefined.";
end;
div(f:SAME):SAME is -- The quotient of self and `f'. Built-in.
raise "FLTD::div(SAME):SAME undefined.";
end;
is_eq(f:SAME):BOOL is -- True if self and `f' represent the same value. Built-in.
raise "FLTD::is_eq(f:SAME):BOOL undefined.";
end;
is_neq(f:SAME):BOOL is
-- True if self and `f' represent different values. Built-in.
-- The treatment of NaNs is ambiguous. IEEE Standard 754 asks
-- that `eq', `lt', `leq', `gt', and `geq' return _false_ if
-- either or both operands are NaNs. The `neq' function is
-- supposed to be the inverse of `eq', so that _true_ is returned
-- if one or both of the arguments is a NaN. Since the standard
-- behavior would seem to be inconsistent with our other
-- comparison functions, we punt and do whatever C does with '!='.
raise "FLTD::is_neq(f:SAME):BOOL undefined.";
end;
is_lt(f:SAME):BOOL is -- True if self is less than `f'. Built-in.
raise "FLTD::is_lt(SAME):BOOL undefined.";
end;
is_leq(f:SAME):BOOL is -- True if self is less than or equal to `f'. Built-in.
raise "FLTD::is_leq(SAME):BOOL undefined.";
end;
is_gt(f:SAME):BOOL is -- True if self is greater than `f' as signed integers. Built-in.
raise "FLTD::is_gt(SAME):BOOL undefined.";
end;
is_geq(f:SAME):BOOL is -- True if self is greater than or equal to `f'. Built-in.
raise "FLTD::is_geq(SAME):BOOL undefined.";
end;
is_within(tolerance,val:SAME):BOOL is
return (self-val).abs<=tolerance;
end;
-- IEEE functions.
is_finite:BOOL is -- returns true if zero, subnormal or normal.
return C_FLTD::finite(self);
end;
is_inf:BOOL is -- returns true if infinite
return C_FLTD::isinf(self);
end;
is_nan:BOOL is -- returns true if NaN
return C_FLTD::isnan(self);
end;
is_normal:BOOL is -- returns true if normal
return C_FLTD::isnormal(self);
end;
is_subnormal:BOOL is -- returns true if subnormal
return C_FLTD::issubnormal(self);
end;
is_zero:BOOL is -- returns true is zero
return C_FLTD::iszero(self);
end;
signbit_set:BOOL is -- returns true if sign bit of self is set
return C_FLTD::signbit(self);
end;
unbiased_exponent:INT is
-- return unbiased exponent of self as an INT;
-- for zero this is INT::maxint.negate, for an
-- infinite it is INT::maxint. If subnormal,
-- normalization occurs first.
return C_FLTD::ilogb(self);
end;
copysign(y:SAME):SAME is
-- return self with the sign bit set to the same as y's sign bit.
return C_FLTD::copysign(self,y);
end;
nextup:FLTD is -- return next representable number from self.
return C_FLTD::nextafter(self,1.fltd);
end;
nextdown:FLTD is -- return previous representable number from self.
return C_FLTD::nextafter(self,-1.fltd);
end;
-- x.remainder(y) and x.mod(y) return a remainder of x with respect
-- to y; that is, the result r is one of the numbers that differ from
-- x by an integral multiple of y. Thus (x-r)/y is an integral
-- value, even though it might exceed INT::maxint if it were
-- explicitly computed as an INT. Both functions return one of the
-- two such r smallest in magnitude. remainder(x,y) is the operation
-- specified in ANSI/IEEE Std 754-1985; the result of x.mod(y) may
-- differ from remainder's result by +-y. The magnitude of
-- remainder's result can not exceed half that of y; its sign might
-- not agree with either x or y. The magnitude of mod's result is
-- less than that of y; its sign agrees with that of x. Neither
-- function will raise an exception as long as both arguments are
-- normal or subnormal. x.remainder(0), x.mod(0), oo.remainder(y),
-- and oo.mod(y) are invalid operations that produce a NaN.
remainder(y:FLTD):FLTD is
return C_FLTD::remainder(self,y);
end;
mod(y:FLTD):FLTD is
return C_FLTD::fmod(self,y);
end;
scale_by(n:INT):FLTD is
-- return x*2.pow(n) computed by exponent manipulation rather
-- than by actually performing an exponentiation or a multiplication.
-- 1 <= x.abs.scale_by(-x.unbiased_exponent) < 2 for every x
-- except 0, infinity, and NaN.
return C_FLTD::scalbn(self,n);
end;
-- Bessel functions of the first and second kinds. y0, y1 and yn have
-- logarithmic singularities at the origin, so they treat zero and
-- negative arguments the way log does.
bessel_j0:SAME is
return C_FLTD::j0(self);
end;
bessel_j1:SAME is
return C_FLTD::j1(self);
end;
bessel_jn(n:INT):SAME is
return C_FLTD::jn(n,self);
end;
bessel_y0:SAME is
return C_FLTD::y0(self);
end;
bessel_y1:SAME is
return C_FLTD::y0(self);
end;
bessel_yn(n:INT):SAME is
return C_FLTD::yn(n,self);
end;
-- Error functions
erf:SAME is
-- error function x.erf = (1/sqrt(pi))*integrate(0,x,exp(-t^2)dt)
return C_FLTD::erf(self);
end;
one_minus_erf:SAME is
-- 1.0-self.erf, but computed in a way to avoid cancellation for large self.
return C_FLTD::erfc(self);
end;
-- Exponential, logarithm, power functions. All these functions handle
-- exceptional arguments in the spirit of IEEE 754-1985. So:
-- 0.log is -infinity with a division by zero exception
-- For x<0, including -infinity, x.log is a quiet NaN with an invalid op exception
-- For x=+infinity or a quiet NaN, x.log is x without exception
-- For a signaling NaN, x.log is a quiet NaN with an invalid op exception
-- 1.log is zero without exception
-- For any other positive x, x.log is a normalized number with an inexact exception
exp:SAME is -- The exponential e^self.
return(C_FLTD::exp(self));
end;
exp_minus_one:SAME is -- e^self-1.0, accurate even for tiny self.
return(C_FLTD::expm1(self));
end;
exp2:SAME is -- 2^self
return(C_FLTD::exp2(self));
end;
exp10:SAME is -- 10^self
return(C_FLTD::exp10(self));
end;
log:SAME is -- The natural logarithm of self.
return(C_FLTD::log(self));
end;
plus_one_log:SAME is -- (self+1).log, accurate even for tiny self.
return(C_FLTD::log1p(self));
end;
log2:SAME is -- The logarithm base two of self.
return log10/log10_2;
end;
log10:SAME is -- The logarithm base ten of self.
return(C_FLTD::log10(self));
end;
pow(arg:SAME):SAME is
-- self raised to the arg'th power. x.pow(0.0)=1.0 for all x.
return(C_FLTD::pow(self,arg));
end;
-- Hyperbolic functions. They handle exceptional arguments in the
-- spirit of IEEE 754-1985. So:
-- sinh and cosh return +-infinity on overflow
-- acosh returns a NaN if its argument is less than 1.0
-- atanh returns a NaN if its argument has an absolute value >1.0
sinh:SAME is -- The hyperbolic sine of self.
return(C_FLTD::sinh(self));
end;
cosh:SAME is -- The hyperbolic cosine of self.
return(C_FLTD::cosh(self));
end;
tanh:SAME is -- The hyperbolic tangent of self.
return(C_FLTD::tanh(self));
end;
asinh:SAME is -- The inverse hyperbolic sine of self.
return(C_FLTD::asinh(self));
end;
acosh:SAME is -- The inverse hyperbolic cosine of self.
return(C_FLTD::acosh(self));
end;
atanh:SAME is -- The inverse hyperbolic tangent of self.
return(C_FLTD::atanh(self));
end;
-- Trigonometric functions. These functions handle exceptional arguments
-- in the spirit of IEEE 754-1985. So:
-- +-infinity.sin, +-infinity.cos, +-infinity.tan return NaN
-- x.asin and x.acos with x.abs>1 return NaN
-- sinpi etc. are similar except they compute self.sinpi=(self*pi).sin avoiding
-- range-reduction issues because their definition permits range reduction
-- that is fast and exact for all self. The corresponding inverse functions
-- compute asinpi(x)
hypot(arg:SAME):SAME is
-- sqrt(self*self+arg*arg), taking precautions against unwarranted
-- IEEE exceptions. +-infinity.hypot(arg) is +infinity for any arg,
-- even a NaN, and is exceptional only for a signaling NaN.
return(C_FLTD::hypot(self,arg));
end;
sin:SAME is
return(C_FLTD::sin(self));
end;
cos:SAME is
return(C_FLTD::cos(self));
end;
--sincos:TUP{SAME,SAME} is
-- Simultaneous computation of self.sin and self.cos. This is faster
-- than independently computing them.
-- return(C_FLTD::c_fltd_sincos(self));
-- end;
tan:SAME is
return(C_FLTD::tan(self));
end;
asin:SAME is -- The arc sine of self in the range [-pi/2, pi/2]
return(C_FLTD::asin(self));
end;
acos:SAME is -- The arc sine of self in the range [0.0, pi]
return(C_FLTD::acos(self));
end;
atan:SAME is -- The arc tangent of self in the range [-pi/2, pi/2].
return(C_FLTD::atan(self));
end;
atan2(f:SAME):SAME is
-- The arc tangent of self divided by f in the range [-pi, pi].
-- It chooses the quadrant specified by (self, arg).
return(C_FLTD::atan2(self,f));
end;
sinpi:SAME is
return(C_FLTD::sinpi(self));
end;
cospi:SAME is
return(C_FLTD::cospi(self));
end;
-- sincospi:TUP{SAME,SAME} is
-- Simultaneous computation of self.sinpi and self.cospi. This is faster
-- than independently computing them.
-- return(C_FLTD::c_fltd_sincospi(self));
-- end;
tanpi:SAME is
return(C_FLTD::tanpi(self));
end;
asinpi:SAME is
-- (1/pi) times the arc sine of self.
-- Result in the range [-1/2, 1/2]
return(C_FLTD::asinpi(self));
end;
acospi:SAME is
-- (1/pi) times the arc cosine of self.
-- Result in the range [0, 1]
return(C_FLTD::acospi(self));
end;
atanpi:SAME is
-- (1/pi) times the arc tangent of self.
-- Result in the range [-1/2, 1/2]
return(C_FLTD::atanpi(self));
end;
atan2pi(f:SAME):SAME is
-- (1/pi) times the arc tangent of self divided by f.
-- Result in the range [-1, 1].
-- It chooses the quadrant specified by (self, arg).
return(C_FLTD::atan2pi(self,f));
end;
-- Miscellaneous
abs:SAME is -- The absolute value of self.
return(C_FLTD::fabs(self));
end;
signum:SAME is
if self<0.0d then return -1.0d;
elsif self>0.0d then return 1.0d;
-- else return self; -- NLP
end; return self; -- NLP
-- end; -- NLP
end;
log_gamma:SAME is
-- log gamma function. x.ln_gamma=x.gamma.abs.log
return(C_FLTD::lgamma(self));
end;
gamma:SAME is
-- gamma function.
if self>0.0d then return log_gamma.exp;
elsif integral then return 0.0d; -- ? Is this correct?
elsif abs.floor.int.is_even then return -log_gamma.exp;
-- else return log_gamma.exp; -- NLP
end; return log_gamma.exp; -- NLP
-- end; -- NLP
end;
sqrt:SAME is -- The square root of self.
return(C_FLTD::sqrt(self));
end;
square:SAME is -- The square of self.
return self*self;
end;
cube_root:SAME is -- The square root of self.
return(C_FLTD::cbrt(self));
end;
cube:SAME is -- The cube of self.
return self*self*self;
end;
max(arg:SAME):SAME is -- The larger of self and arg.
-- This is incorrect if one argument is a NaN.
-- if self<arg then return arg; else return self; end; -- NLP
if self<arg then return arg; end; return self; -- NLP
end;
min(arg:SAME):SAME is -- The smaller of self and arg.
-- This is incorrect if one argument is a NaN.
-- if self<arg then return self; else return arg; end; -- NLP
if self<arg then return self; end; return arg; -- NLP
end;
-- Conversions.
private shared fdbuf: FSTR; -- Buffer for temporary writing of floats
str:STR is
-- A string version of self.
if ((void(fdbuf)) or (fdbuf.size < 30)) then fdbuf := #FSTR(30) end;
fstr ::= str_in(fdbuf);
return(fstr.str); end;
str(prec:INT):STR is
-- A string version of self with "prec" digits of precision.
des_sz ::= prec+10;
if ((void(fdbuf)) or (fdbuf.size<des_sz)) then
fdbuf:=#FSTR(des_sz) end;
fstr ::= str_in(fdbuf,prec);
return(fstr.str); end;
str_in(arg:FSTR):FSTR is
-- Return an FSTR representation of self using the space in
-- arg if possible
store_in: FSTR;
if (arg.size >= 30) then store_in := arg;
else store_in := #FSTR(30) end;
sz ::= C_FLTD::c_fltd_str_in(self, store_in);
store_in.loc := sz;
return(store_in); end;
str_in(arg:FSTR, prec: INT): FSTR is
-- Return FSTR version of self with precicsion of "prec" using the
-- space in arg if possible.
store_in: FSTR;
des_sz ::= prec+10;
if (arg.size > des_sz) then store_in := arg
else store_in := #FSTR(des_sz) end;
sz ::= C_FLTD::c_fltd_str_in_prec(self,store_in,prec);
store_in.loc := sz;
return(store_in); end;
create (s: STR): SAME is
return C_FLTD::atof(s)
end;
int:INT post result.fltd=self is
-- INT version of self. It is an error if self is not integral.
-- Use truncate, floor, ceiling, or round to achieve this.
return C_FLTD::c_fltd_int(self);
end;
integral:BOOL is
-- Return true if self is integral.
return self=truncate;
end;
flt:FLT is
-- A floating point version of self. It is an error if the
-- value cannot be held in a FLT. Built-in.
raise "FLTD::flt:FLT undefined." end;
fltx:FLTX is
-- An extended floating point version of self. It is an
-- error if the value cannot be held in a FLTX. Built-in.
raise "FLTD::fltx:FLTX undefined." end;
fltdx:FLTDX is
-- An extended floating point version of self. Built-in.
raise "FLTD::fltdx:FLTDX undefined." end;
truncate:SAME is -- The nearest integer toward zero.
return C_FLTD::aint(self);
end;
floor:SAME is -- The largest integer not greater than self.
return C_FLTD::floor(self);
end;
ceiling:SAME is -- The smallest integer not less than self.
return C_FLTD::ceil(self);
end;
round:SAME is -- The closest integer to self.
return C_FLTD::rint(self);
end;
-- Special values.
pi:SAME is
-- An approximation of the mathematical value "pi". Built-in.
raise "FLTD::pi:FLTD undefined";
end;
e:SAME is
-- An approximation of the base of the natural logarithms "e". Built-in.
raise "FLTD::e:FLTD undefined";
end;
sqrt_2:SAME is
-- Approximation of 2.sqrt. Built-in.
raise "FLTD::sqrt_2:FLTD undefined";
end;
log_2:SAME is
-- Approximation of 2.log. Built-in.
raise "FLTD::log_2:FLTD undefined";
end;
log2_e:SAME is
-- Approximation of e.log2. Built-in.
raise "FLTD::log2_e:FLTD undefined";
end;
log10_e:SAME is
-- Approximation of e.log10. Built-in.
raise "FLTD::log10_e:FLTD undefined";
end;
const log10_2:SAME:=(2.0d).log10;
-- Approximation of 2.0.log10.
log_10:SAME is
-- Approximation of 10.log. Built-in.
raise "FLTD::log_10:FLTD undefined";
end;
half_pi:SAME is
-- Approximation of pi/2. Built-in.
raise "FLTD::half_pi:FLTD undefined";
end;
quarter_pi:SAME is
-- Approximation of pi/4. Built-in.
raise "FLTD::quarter_pi:FLTD undefined";
end;
inv_sqrt_2:SAME is
-- Approximation of 1/(2.sqrt). Built-in.
raise "FLTD::inv_sqrt_2:FLTD undefined";
end;
inv_pi:SAME is
-- Approximation of 1/pi. Built-in.
raise "FLTD::inv_pi:FLTD undefined";
end;
double_inv_pi:SAME is
-- Approximation of 2/pi. Built-in.
raise "FLTD::double_inv_pi:FLTD undefined";
end;
double_sqrt_pi:SAME is
-- Approximation of 2*(pi.sqrt). Built-in.
raise "FLTD::double_sqrt_pi:FLTD undefined";
end;
-- The value to be used to represent no element in sets.
const nil:SAME:=signaling_NaN(0);
signaling_NaN(sig:INT):SAME is
-- IEEE signalling NaN. `sig' is the significand (presently unused).
return C_FLTD::signaling_nan(sig);
end;
quiet_NaN(sig:INT):SAME is
-- IEEE quiet NaN. `sig' is the significand (presently unused).
return C_FLTD::quiet_nan(sig);
end;
infinity:SAME is -- IEEE Infinity.
return C_FLTD::infinity;
end;
const epsilon:SAME:=2.2204460492503131e-16d; -- The minimum x>0.0 such that 1.0+x/=x.
const digits:INT:=15; -- The number of decimal digits of precision.
-- The number of bits in the significand, including an implied bit.
const mantissa_bits:INT:=53;
-- The smallest normalized positive number.
const min_normal:SAME:=2.2250738585072014e-308d;
-- The largest normalized positive number.
const max_normal:SAME:=1.7976931348623157e308d;
min_subnormal:SAME is -- The smallest subnormal positive number.
return C_FLTD::min_subnormal;
end;
max_subnormal:SAME is -- The largest subnormal positive number.
return C_FLTD::max_subnormal;
end;
-- The minimum negative integer x such that b^(x-1) is in the range
-- of normalized floating point numbers.
const min_exp:INT:=-1021;
-- The minimum x such that 10^x is in the range of normalized
-- floating point numbers.
const min_exp10:INT:=-307;
const max_exp:INT:=1024; -- The maximum allowable exponent.
const max_exp10:INT:=308; -- The maximum x such that 10^x is within range.
-- Useful iters
sum!(i:SAME!):SAME is
-- Yields the sum of all previous values of `i'.
r::=0.0d; loop r:=r+i; yield r end end;
product!(i:SAME!):SAME is
-- Yields the product of all previous values of `i'.
r::=1.0d; loop r:=r*i; yield r end end;
end; -- class FLTD
-------------------------------------------------------------------
external class C_FLTD is
-- This corresponds to the standard math functions linkable with "-lm".
finite(a:FLTD):BOOL;
isinf(a:FLTD):BOOL;
isnan(a:FLTD):BOOL;
iszero(a:FLTD):BOOL;
isnormal(a:FLTD):BOOL;
issubnormal(a:FLTD):BOOL;
signbit(a:FLTD):BOOL;
ilogb(a:FLTD):INT;
copysign(a:FLTD,b:FLTD):FLTD;
nextafter(a:FLTD,b:FLTD):FLTD;
remainder(a:FLTD,b:FLTD):FLTD;
fmod(a:FLTD,b:FLTD):FLTD;
scalbn(a:FLTD,b:INT):FLTD;
j0(a:FLTD):FLTD;
j1(a:FLTD):FLTD;
jn(a:INT,b:FLTD):FLTD;
y0(a:FLTD):FLTD;
y1(a:FLTD):FLTD;
yn(a:INT,b:FLTD):FLTD;
erf(a:FLTD):FLTD;
erfc(a:FLTD):FLTD;
exp(a:FLTD):FLTD;
expm1(a:FLTD):FLTD;
exp2(a:FLTD):FLTD;
exp10(a:FLTD):FLTD;
log(a:FLTD):FLTD;
log1p(a:FLTD):FLTD;
log10(a:FLTD):FLTD;
pow(a:FLTD,b:FLTD):FLTD;
sinh(a:FLTD):FLTD;
cosh(a:FLTD):FLTD;
tanh(a:FLTD):FLTD;
asinh(a:FLTD):FLTD;
acosh(a:FLTD):FLTD;
atanh(a:FLTD):FLTD;
hypot(a:FLTD,b:FLTD):FLTD;
sin(a:FLTD):FLTD;
cos(a:FLTD):FLTD;
--c_fltd_sincos(a:FLTD):TUP{FLTD,FLTD};
tan(a:FLTD):FLTD;
asin(a:FLTD):FLTD;
acos(a:FLTD):FLTD;
atan(a:FLTD):FLTD;
atan2(a:FLTD,b:FLTD):FLTD;
sinpi(a:FLTD):FLTD;
cospi(a:FLTD):FLTD;
--c_fltd_sincospi(a:FLTD):TUP{FLTD,FLTD};
tanpi(a:FLTD):FLTD;
asinpi(a:FLTD):FLTD;
acospi(a:FLTD):FLTD;
atanpi(a:FLTD):FLTD;
atan2pi(a:FLTD,b:FLTD):FLTD;
fabs(a:FLTD):FLTD;
lgamma(a:FLTD):FLTD;
sqrt(a:FLTD):FLTD;
cbrt(a:FLTD):FLTD;
aint(a:FLTD):FLTD;
floor(a:FLTD):FLTD;
ceil(a:FLTD):FLTD;
rint(a:FLTD):FLTD;
signaling_nan(a:INT):FLTD;
quiet_nan(a:INT):FLTD;
infinity:FLTD;
min_subnormal:FLTD;
max_subnormal:FLTD;
c_fltd_int(a:FLTD):INT;
c_fltd_str_in(f: FLTD, store_in: FSTR): INT;
c_fltd_str_in_prec(f: FLTD, store_in: FSTR, precision: INT): INT;
atof(s: STR): FLTD;
end;
-------------------------------------------------------------------
class TEST_FLTD is
include TEST;
main is
class_name("FLTD");
test("str 1",(0.1234567d).str,"0.123457"); -- ok? davids or om must
-- verify that this is the desired behaviour.
test("str prec=2",(-1234.12345d).str(2),"-1.2e+03");
test("str prec=3",(-1234.12345d).str(3),"-1.23e+03");
test("str prec=4",(1234.12345d).str(4),"1234");
test("str prec=5",(1234.12345d).str(5),"1234.1");
test("str prec=6",(1234.12345d).str(6),"1234.12");
finish;
end;
end; -- class TEST_FLTD
-------------------------------------------------------------------