IPRealImpl.mesa
Copyright © 1984, 1985 Xerox Corporation. All rights reserved.
Doug Wyatt, May 20, 1985 2:08:58 pm PDT
Michael Plass, October 9, 1985 12:05:25 pm PDT
DIRECTORY
Basics USING [LongMult],
IPReal USING [Rational, ShortRational],
Real USING [Fix, RealException],
RealFns USING [AlmostEqual],
RuntimeError USING [BoundsFault]
;
IPRealImpl: CEDAR PROGRAM
IMPORTS Basics, Real, RealFns, RuntimeError
EXPORTS IPReal
~ BEGIN
Fix:
PRIVATE
PROC[r:
REAL]
RETURNS[
INT] ~ {
RETURN[Real.Fix[r]] };
This procedure copes with a "feature" of Mesa's signal handling. Because Real.Fix actually compiles into machine code, any signal it raises cannot be caught in the statement that invokes it; the catch phrase must be at least one procedure call away. To fix a real number and catch any exception, say Fix[r ! Real.RealException => GOTO Fail];
Floor:
PUBLIC
PROC[a:
REAL]
RETURNS[c:
REAL] ~ {
c ← Fix[a ! Real.RealException => { c ← a; CONTINUE }];
IF c>a THEN RETURN[c-1] ELSE RETURN[c]
};
Ceiling:
PUBLIC
PROC[a:
REAL]
RETURNS[c:
REAL] ~ {
c ← Fix[a ! Real.RealException => { c ← a; CONTINUE }];
IF c<a THEN RETURN[c+1] ELSE RETURN[c]
};
Trunc:
PUBLIC
PROC[a:
REAL]
RETURNS[c:
REAL] ~ {
c ← Fix[a ! Real.RealException => { c ← a; CONTINUE }];
RETURN[c]
};
Round:
PUBLIC
PROC[a:
REAL]
RETURNS[c:
REAL] ~ {
RETURN[Floor[a + 0.5]]
};
Mod:
PUBLIC
PROC[a, b:
REAL]
RETURNS[
REAL] ~ {
RETURN[a - b*Floor[a/b]]
};
Rem:
PUBLIC
PROC[a, b:
REAL]
RETURNS[
REAL] ~ {
RETURN[a - b*Trunc[a/b]]
};
Inverse:
PROC [real:
REAL]
RETURNS [
REAL] ~ {
RETURN [1.0/real]};
This is a separate procedure to make sure that exceptions gets caught.
FloorN:
PROC [real:
REAL]
RETURNS [
NAT] ~ {
RETURN [Real.Fix[real]]};
This is a separate procedure to make sure that exceptions gets caught.
Works correctly for non-negative arguments only.
ShortRationalFromReal:
PUBLIC
PROC [real:
REAL]
RETURNS [ans: IPReal.ShortRational] ~ {
abs: REAL ~ ABS[real];
p: NAT ← 1;
q: CARDINAL ← 0;
BEGIN
ENABLE Real.RealException, RuntimeError.BoundsFault =>
GOTO Done;
f: NAT ← FloorN[abs];
r: REAL ← abs-f;
pp: NAT ← p;
qq: CARDINAL ← q;
p ← f;
q ← 1;
WHILE r # 0
DO
rinv: REAL ← Inverse[r];
fnew: NAT ← FloorN[rinv];
pnew: LONG CARDINAL ← Basics.LongMult[fnew, p] + pp;
qnew: LONG CARDINAL ← Basics.LongMult[fnew, q] + qq;
IF pnew > NAT.LAST OR qnew > CARDINAL.LAST THEN EXIT;
pp ← p;
qq ← q;
p ← pnew;
q ← qnew;
r ← rinv - fnew;
ENDLOOP;
EXITS Done => NULL;
END;
ans.numerator ← p;
ans.denominator ← q;
IF real < 0 THEN ans.numerator ← -ans.numerator;
};
mantissaBits:
INTEGER ← MantissaBits[];
MantissaBits:
PROC
RETURNS [n:
INTEGER] ~ {
f: REAL ← 0.5;
n ← 0;
WHILE 1.0 - f # 1.0
DO
f ← f/2;
n ← n + 1;
ENDLOOP;
};
bigInt:
INT ← Real.Fix[
REAL[
LAST[
INT]/256*256]];
-- Fix of largest real that can be fixed.
RationalFromReal:
PUBLIC
PROC [real:
REAL]
RETURNS [ans: IPReal.Rational] ~ {
abs: REAL ~ ABS[real];
p: REAL ← 1;
q: REAL ← 0;
BEGIN
ENABLE Real.RealException, RuntimeError.BoundsFault =>
GOTO Done;
f: REAL ← Trunc[abs];
r: REAL ← abs-f;
pp: REAL ← p;
qq: REAL ← q;
p ← f;
q ← 1;
UNTIL RealFns.AlmostEqual[p, abs*q, 3-mantissaBits]
DO
rinv: REAL ← Inverse[r];
fnew: REAL ← Trunc[rinv];
pnew: REAL ← fnew*p + pp;
qnew: REAL ← fnew*q + qq;
IF pnew > bigInt OR qnew > bigInt THEN EXIT;
pp ← p;
qq ← q;
p ← pnew;
q ← qnew;
r ← rinv - fnew;
ENDLOOP;
EXITS Done => NULL;
END;
ans.numerator ← Real.Fix[p];
ans.denominator ← Real.Fix[q];
IF real < 0 THEN ans.numerator ← -ans.numerator;
};
END.