(* $Id: LowLReal.Mod,v 1.6 1999/09/02 13:15:35 acken Exp $ *) MODULE oocLowLReal; (* ToDo. support 64 bit builds *) (* LowLReal - Gives access to the underlying properties of the type LONGREAL for IEEE double-precision numbers. Copyright (C) 1996 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 Low := oocLowReal, S := SYSTEM; (* 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*= 53; expoMax*= 1023; expoMin*= 1-expoMax; large*= MAX(LONGREAL); (*1.7976931348623157D+308;*) (* MAX(LONGREAL) *) (*small*= 2.2250738585072014D-308;*) small*= 2.2250738585072014/9.9999999999999981D307(*/10^308)*); 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; ONE=1.0D0; (* some commonly-used constants *) ZERO=0.0D0; TEN=1.0D1; DEBUG = TRUE; expOffset=expoMax; hiBit=19; expBit=hiBit+1; nMask={0..hiBit,31}; (* number mask *) expMask={expBit..30}; (* exponent mask *) TYPE Modes*= SET; LongInt=ARRAY 2 OF LONGINT; LongSet=ARRAY 2 OF SET; VAR (*sml* : LONGREAL; tmp: LONGREAL;*) (* this was a test to get small as a variable at runtime. obviously, compile time preferred; -- noch *) isBigEndian-: BOOLEAN; (* set when target is big endian *) (* PROCEDURE power0(i, j : INTEGER) : LONGREAL; (* used to calculate sml at runtime; -- noch *) VAR k : INTEGER; p : LONGREAL; BEGIN k := 1; p := i; REPEAT p := p * i; INC(k); UNTIL k=j; RETURN p; END power0; *) (* Errors are handled through the LowReal module *) PROCEDURE err*(): INTEGER; BEGIN RETURN Low.err END err; PROCEDURE ClearError*; BEGIN Low.ClearError END ClearError; PROCEDURE ErrorHandler*(err: INTEGER); BEGIN Low.ErrorHandler(err) END ErrorHandler; (* type-casting utilities *) PROCEDURE Move (VAR x: LONGREAL; VAR ra: ARRAY OF LONGINT); (* typecast a LONGREAL to an array of LONGINTs *) VAR t: LONGINT; BEGIN S.MOVE(S.ADR(x),S.ADR(ra),SIZE(LONGREAL)); IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END END Move; PROCEDURE MoveSet (VAR x: LONGREAL; VAR ra: ARRAY OF SET); (* typecast a LONGREAL to an array of LONGINTs *) VAR t: SET; BEGIN S.MOVE(S.ADR(x),S.ADR(ra),SIZE(LONGREAL)); IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END END MoveSet; (* Note: The below should be done with a type cast -- once the compiler supports such things. *) (*<* PUSH; Warnings := FALSE *>*) PROCEDURE Real * (ra: ARRAY OF LONGINT): LONGREAL; (* typecast an array of big endian LONGINTs to a LONGREAL *) VAR t: LONGINT; x: LONGREAL; BEGIN IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END; S.MOVE(S.ADR(ra),S.ADR(x),SIZE(LONGREAL)); RETURN x END Real; PROCEDURE ToReal (ra: ARRAY OF SET): LONGREAL; (* typecast an array of LONGINTs to a LONGREAL *) VAR t: SET; x: LONGREAL; BEGIN IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END; S.MOVE(S.ADR(ra),S.ADR(x),SIZE(LONGREAL)); RETURN x END ToReal; (*<* POP *> *) PROCEDURE exponent*(x: LONGREAL): 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. *) VAR ra: LongInt; BEGIN (* NOTE: x=0.0 should raise exception *) IF x=ZERO THEN RETURN 0 ELSE Move(x, ra); RETURN SHORT(S.LSH(ra[0],-expBit) MOD 2048)-expOffset END END exponent; PROCEDURE exponent10*(x: LONGREAL): 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 IF x=ZERO THEN RETURN 0 END; (* exception could be raised here *) exp:=0; x:=ABS(x); WHILE x>=TEN DO x:=x/TEN; INC(exp) END; WHILE x<1 DO x:=x*TEN; DEC(exp) END; RETURN exp END exponent10; PROCEDURE fraction*(x: LONGREAL): LONGREAL; (* 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}; VAR ra: LongInt; BEGIN IF x=ZERO THEN RETURN ZERO ELSE Move(x, ra); ra[0]:=S.VAL(LONGINT, S.VAL(SET,ra[0])*nMask+eZero); RETURN Real(ra)*2.0D0 END END fraction; PROCEDURE IsInfinity * (real: LONGREAL) : BOOLEAN; CONST signMask={0..30}; VAR ra: LongSet; BEGIN MoveSet(real, ra); RETURN (ra[0]*signMask=expMask) & (ra[1]={}) END IsInfinity; PROCEDURE IsNaN * (real: LONGREAL) : BOOLEAN; CONST fracMask={0..hiBit}; VAR ra: LongSet; BEGIN MoveSet(real, ra); RETURN (ra[0]*expMask=expMask) & ((ra[1]#{}) OR (ra[0]*fracMask#{})) END IsNaN; PROCEDURE sign*(x: LONGREAL): LONGREAL; (* 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