(* $Id: LowReal.Mod,v 1.5 1999/09/02 13:17:38 acken Exp $ *) MODULE oocLowReal; (* LowReal - Gives access to the underlying properties of the type REAL for IEEE single-precision numbers. Copyright (C) 1995 Michael Griebling This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) IMPORT S := SYSTEM, Console; (* Real number properties are defined as follows: radix--The whole number value of the radix used to represent the corresponding read number values. places--The whole number value of the number of radix places used to store values of the corresponding real number type. expoMin--The whole number value of the exponent minimum. expoMax--The whole number value of the exponent maximum. large--The largest value of the corresponding real number type. small--The smallest positive value of the corresponding real number type, represented to maximal precision. IEC559--A Boolean value that is TRUE if and only if the implementation of the corresponding real number type conforms to IEC 559:1989 (IEEE 754:1987) in all regards. NOTES 6 -- If `IEC559' is TRUE, the value of `radix' is 2. 7 -- If LowReal.IEC559 is TRUE, the 32-bit format of IEC 559:1989 is used for the type REAL. 7 -- If LowLong.IEC559 is TRUE, the 64-bit format of IEC 559:1989 is used for the type REAL. LIA1--A Boolean value that is TRUE if and only if the implementation of the corresponding real number type conforms to ISO/IEC 10967-1:199x (LIA-1) in all regards: parameters, arithmetic, exceptions, and notification. rounds--A Boolean value that is TRUE if and only if each operation produces a result that is one of the values of the corresponding real number type nearest to the mathematical result. gUnderflow--A Boolean value that is TRUE if and only if there are values of the corresponding real number type between 0.0 and `small'. exception--A Boolean value that is TRUE if and only if every operation that attempts to produce a real value out of range raises an exception. extend--A Boolean value that is TRUE if and only if expressions of the corresponding real number type are computed to higher precision than the stored values. nModes--The whole number value giving the number of bit positions needed for the status flags for mode control. *) CONST radix*= 2; places*= 24; expoMax*= 127; expoMin*= 1-expoMax; large*= MAX(REAL);(*3.40282347E+38;*) (* MAX(REAL) *) (*small*= 1.17549435E-38; (* 2^(-126) *)*) small* = 1/8.50705917E37; (* don't know better way; -- noch *) IEC559*= TRUE; LIA1*= FALSE; rounds*= FALSE; gUnderflow*= TRUE; (* there are IEEE numbers smaller than `small' *) exception*= FALSE; (* at least in the default implementation *) extend*= FALSE; nModes*= 0; TEN=10.0; (* some commonly-used constants *) ONE=1.0; ZERO=0.0; expOffset=expoMax; hiBit=22; expBit=hiBit+1; nMask={0..hiBit,31}; (* number mask *) expMask={expBit..30}; (* exponent mask *) TYPE Modes*= SET; VAR (*small* : REAL; tmp: REAL;*) (* this was a test to get small as a variable at runtime. obviously, compile time preferred; -- noch *) ErrorHandler*: PROCEDURE (errno : INTEGER); err-: INTEGER; (* Error handler default stub which can be replaced *) (* PROCEDURE power0(i, j : INTEGER) : REAL; (* used to calculate sml at runtime; -- noch *) VAR k : INTEGER; p : REAL; BEGIN k := 1; p := i; REPEAT p := p * i; INC(k); UNTIL k=j; RETURN p; END power0;*) PROCEDURE DefaultHandler (errno : INTEGER); BEGIN err:=errno END DefaultHandler; PROCEDURE ClearError*; BEGIN err:=0 END ClearError; PROCEDURE exponent*(x: REAL): INTEGER; (* The value of the call exponent(x) shall be the exponent value of `x' that lies between `expoMin' and `expoMax'. An exception shall occur and may be raised if `x' is equal to 0.0. *) BEGIN (* NOTE: x=0.0 should raise exception *) IF x=ZERO THEN RETURN 0 ELSE RETURN SHORT(S.LSH(S.VAL(LONGINT,x),-expBit) MOD 256)-expOffset END END exponent; PROCEDURE exponent10*(x: REAL): INTEGER; (* The value of the call exponent10(x) shall be the base 10 exponent value of `x'. An exception shall occur and may be raised if `x' is equal to 0.0. *) VAR exp: INTEGER; BEGIN exp:=0; x:=ABS(x); IF x=ZERO THEN RETURN exp END; (* exception could be raised here *) WHILE x>=TEN DO x:=x/TEN; INC(exp) END; WHILE (x>ZERO) & (x<1.0) DO x:=x*TEN; DEC(exp) END; RETURN exp END exponent10; PROCEDURE fraction*(x: REAL): REAL; (* The value of the call fraction(x) shall be the significand (or significant) part of `x'. Hence the following relationship shall hold: x = scale(fraction(x), exponent(x)). *) CONST eZero={(hiBit+2)..29}; BEGIN IF x=ZERO THEN RETURN ZERO ELSE RETURN S.VAL(REAL,(S.VAL(SET,x)*nMask)+eZero)*2.0 (* set the mantissa's exponent to zero *) END END fraction; PROCEDURE IsInfinity * (real: REAL) : BOOLEAN; CONST signMask={0..30}; BEGIN RETURN S.VAL(SET,real)*signMask=expMask END IsInfinity; PROCEDURE IsNaN * (real: REAL) : BOOLEAN; CONST fracMask={0..hiBit}; VAR sreal: SET; BEGIN sreal:=S.VAL(SET, real); RETURN (sreal*expMask=expMask) & (sreal*fracMask#{}) END IsNaN; PROCEDURE sign*(x: REAL): REAL; (* The value of the call sign(x) shall be 1.0 if `x' is greater than 0.0, or shall be -1.0 if `x' is less than 0.0, or shall be either 1.0 or -1.0 if `x' is equal to 0.0. *) BEGIN IF xexpoMax THEN RETURN large*sign(x) (* exception raised here *) ELSIF exp