-- IeeeFloatA.mesa -- Last Modified: Stewart 17-Nov-81 1:14:34 -- Mesa implementation of floating point ops +, -, *, /, Rem DIRECTORY Ieee, Inline, Real USING [ AddInfinityNaN, DivideInfinityNaN, MinusZero, MultiplyInfinityNaN, NoExceptions, NumberType, PlusZero], RealOps; IeeeFloatA: PROGRAM IMPORTS Ieee, Inline EXPORTS RealOps = BEGIN OPEN Ieee, Inline, Real, RealOps; AddNormal: PROC [x, y: POINTER TO Ext] = { ediff: INTEGER ← x.exp - y.exp; normalized: BOOLEAN; IF ediff > 0 THEN DeNormalize[y, -ediff] ELSE {DeNormalize[x, ediff]; x.exp ← y.exp; }; normalized ← Normalized[BITOR[x.frac.highbits, y.frac.highbits]]; IF x.det.sign = y.det.sign THEN { cy: CARDINAL; [cy, x.frac.lowbits] ← ADC2[x.frac.lowbits, y.frac.lowbits]; [cy, x.frac.highbits] ← ADC3[x.frac.highbits, y.frac.highbits, cy]; IF cy # 0 THEN { IF BitOn[x.frac.lowbits, 1] THEN x.frac.lowbits ← Inline.BITOR[x.frac.lowbits, 2]; x.frac.li ← RShift1in1[x.frac.li]; x.exp ← x.exp + 1; }; } ELSE { IF x.frac.lc >= y.frac.lc THEN x.frac.lc ← x.frac.lc - y.frac.lc ELSE {x.frac.lc ← y.frac.lc - x.frac.lc; x.det.sign ← y.det.sign; }; IF x.frac.highbits = 0 AND NOT BitOn[x.frac.lowbits, LowSignificandMask] THEN {x.det.sign ← fpmode.round = rm; x.det.type ← zero; } ELSE {IF normalized THEN PostNormalize[x]; }; }; IF y.det.sticky THEN x.det.sticky ← TRUE; }; FAdd: PUBLIC SAFE PROC [a, b: REAL, m: Mode] RETURNS [REAL] = TRUSTED { x, y: Ext; { fpmode ← m; thisTimeExceptions ← NoExceptions; x ← Unpack[a]; y ← Unpack[b]; IF BitOn[funny, BITOR[x.det, y.det]] THEN SELECT TRUE FROM x.det.type = nan => GOTO RetX; y.det.type = nan => GOTO RetY; x.det.type # infinity AND y.det.type # infinity => NULL; x.det.type = infinity AND y.det.type = infinity => IF fpmode.im = affine AND x.det.sign = y.det.sign THEN GOTO RetA ELSE { SetInvalidOperation[]; x.det.type ← nan; x.frac.lc ← AddInfinityNaN; GOTO RetX; }; x.det.type = infinity => GOTO RetA; y.det.type = infinity => GOTO RetB; ENDCASE => ERROR ELSE SELECT NormalType[x.det, y.det] FROM TNnn => NULL; TNnz => GOTO RetA; TNzn => GOTO RetB; TNzz => RETURN[ IF fpmode.round = rm AND x.det.sign AND y.det.sign THEN MinusZero ELSE PlusZero]; ENDCASE => ERROR; AddNormal[@x, @y]; StepTwo[@x]; GOTO RetX; EXITS RetA => RETURN[a]; RetB => RETURN[b]; RetX => RETURN[Pack[@x]]; RetY => RETURN[Pack[@y]]; }; }; FSub: PUBLIC SAFE PROC [a, b: REAL, m: Mode] RETURNS [REAL] = TRUSTED { -- Negate b LOOPHOLE[b, LongNumber].highbits ← BITXOR[LN[b].highbits, SignBit]; RETURN[FAdd[a, b, m]]; }; FMul: PUBLIC SAFE PROC [a, b: REAL, m: Mode] RETURNS [REAL] = TRUSTED { x, y: Ext; lo: LongNumber; { fpmode ← m; thisTimeExceptions ← NoExceptions; x ← Unpack[a]; y ← Unpack[b]; x.det.sign ← x.det.sign # y.det.sign; -- due to different bias x.exp ← x.exp + y.exp + 1; IF BitOn[funny, BITOR[x.det, y.det]] THEN SELECT TRUE FROM x.det.type = nan => GOTO RetX; y.det.type = nan => GOTO RetY; x.det.type = infinity OR y.det.type = infinity => { IF x.det.type = zero OR y.det.type = zero THEN { SetInvalidOperation[]; x.det.type ← nan; x.frac.lc ← MultiplyInfinityNaN; }; -- Possible test for unnormal zero later. x.det.type ← infinity; GOTO RetX; }; ENDCASE => NULL -- one or more denormalized ELSE SELECT NormalType[x.det, y.det] FROM TNnn => NULL; TNnz => GOTO RetZero; TNzn => GOTO RetZero; TNzz => GOTO RetZero; ENDCASE => ERROR; [x.frac, lo] ← Mul32[x.frac, y.frac]; -- normalize (double normalize??) IF x.frac.lc=0 THEN { x.frac.lc ← lo.lc; x.exp ← x.exp-32; } ELSE {IF lo.lc # 0 THEN x.det.sticky ← TRUE;}; PostNormalize[@x]; StepTwo[@x]; GOTO RetX; EXITS RetX => RETURN[Pack[@x]]; RetY => RETURN[Pack[@y]]; RetZero => RETURN[IF x.det.sign THEN MinusZero ELSE PlusZero]; }; }; FDiv: PUBLIC SAFE PROC [a, b: REAL, m: Mode] RETURNS [c: REAL] = TRUSTED { x, y: Ext; unnormalized: BOOLEAN ← FALSE; { fpmode ← m; thisTimeExceptions ← NoExceptions; x ← Unpack[a]; y ← Unpack[b]; x.det.sign ← x.det.sign # y.det.sign; { IF BitOn[funny, BITOR[x.det, y.det]] THEN { SELECT TRUE FROM x.det.type = nan => GOTO RetX; y.det.type = nan => GOTO RetY; x.det.type = infinity AND y.det.type = infinity => GOTO ZeroDivide; -- possible test for unnormal zero on this one y.det.type = infinity => GOTO RetZero; x.det.type = infinity => GOTO RetX; ENDCASE => IF NOT Normalized[y.frac.highbits] THEN GOTO ZeroDivide; } ELSE SELECT NormalType[x.det, y.det] FROM TNnn => IF Normalized[y.frac.highbits] THEN NULL ELSE GOTO ZeroDivide; -- this is usual flow TNnz => GOTO RetInf; TNzn => GOTO RetZero; TNzz => GOTO ZeroDivide; ENDCASE => ERROR; EXITS ZeroDivide => { SetInvalidOperation[]; x.det.type ← nan; x.frac.lc ← DivideInfinityNaN; GOTO RetX; }; RetInf => {SetDivisionByZero[]; x.det.type ← infinity; GOTO RetX; }; }; -- Have to make sure the numbers are normalized for this to work, so we remember if either was unnormalized (warning). IF NOT Normalized[x.frac.highbits] THEN { PostNormalize[@x]; unnormalized ← TRUE; }; x ← Divide[x, y]; StepTwo[@x]; GOTO RetX; EXITS RetZero => RETURN[IF x.det.sign THEN MinusZero ELSE PlusZero]; RetX => RETURN[Pack[@x]]; RetY => RETURN[Pack[@y]]; }; }; Divide: PROC [a, b: Ext] RETURNS [y: Ext] = { cy: BOOLEAN; Step: PROC = INLINE { y.frac.lc ← y.frac.lc + y.frac.lc; IF cy OR a.frac.lc >= b.frac.lc THEN { a.frac.lc ← a.frac.lc - b.frac.lc; y.frac.lowbits ← y.frac.lowbits + 1; -- can't carry! }; cy ← BitOn[a.frac.highbits, HiBit]; a.frac.lc ← a.frac.lc + a.frac.lc; }; -- initialize IF b.frac.lc = 0 THEN ERROR; y ← a; y.det ← [sign: a.det.sign, sticky: FALSE, blank: 0, type: Real.NumberType[normal]]; y.exp ← a.exp - b.exp; y.frac.lc ← 0; cy ← FALSE; THROUGH [0..32) DO Step[]; ENDLOOP; WHILE NOT BitOn[y.frac.highbits, HiBit] DO -- normalize Step[]; y.exp ← y.exp - 1; ENDLOOP; IF a.frac.lc # 0 THEN y.frac.lowbits ← Inline.BITOR[y.frac.lowbits, 1]; }; FRem: PUBLIC SAFE PROC [a, b: REAL, m: Mode] RETURNS [c: REAL] = TRUSTED { ERROR; }; END. July 8, 1980 6:36 PM, L. Stewart; FRem dummy added August 25, 1980 10:07 AM, L. Stewart; new Divide January 28, 1981 11:50 AM, L. Stewart; Fix to Multiply (denormalized numbers) August 27, 1982 11:24 am, L. Stewart, added TRUSTED everywhere