RationalFromDReal:
PUBLIC
PROC [x:
DREAL, limit:
INT ¬
INT.
LAST]
RETURNS [Rational] = {
... computes the best rational approximation to a real using continued fractions.
|numerator| <= limit, 0 < denominator <= limit.
sign: INT ¬ 1;
inverse: BOOL ¬ FALSE;
p0, q0: INT ¬ 0;
lambda: INT ¬ 0;
q1, p2: INT ¬ 0;
p1, q2: INT ¬ 1;
IF limit < 1 THEN ERROR FloatingPointCommon.Error[other];
IF x > limit THEN RETURN [[limit, 1]];
IF -x > limit THEN RETURN [[-limit, 1]];
IF x < 0.0 THEN { x ¬ -x; sign ¬ -1 };
IF x = 1.0 THEN RETURN [[numerator: sign, denominator: 1]];
IF x > 1.0 THEN { x ¬ 1.0/x; inverse ¬ TRUE };
Here x lies in [0..1), lambda = Fix[x]
DO
oneOverX: DREAL ¬ (x-lambda);
IF oneOverX*(limit-q1) <= q2
THEN
EXIT;
This test ensures that q2 never exceeds limit.
Because the initial x was <1, p2<=q2.
The best approximation so far is p2/q2, and q2 > p2.
x ¬ 1.0/oneOverX;
lambda ¬ DRealSupport.Fix[x];
q0 ¬ q1;
q1 ¬ q2;
q2 ¬ lambda*q1+q0;
p0 ¬ p1;
p1 ¬ p2;
p2 ¬ lambda*p1+p0;
ENDLOOP;
IF
NOT inverse
THEN RETURN [[numerator: sign*p2, denominator: q2]]
ELSE RETURN [[numerator: sign*q2, denominator: p2]];
};