Real for
computations involving numbers other than integers is to develop a special
type for rational numbers -- numerical values that can be
expressed as ratios between integers. It is often possible to arrange a
computation in such a way that all or most of the steps are performed
using the arithmetic of rational numbers, with no rounding error and no
loss of precision during the computation.I'll write ratios as fractions with integer numerators and denominators, and I'll adopt the convention that the denominator should always be positive and that the fraction should always be reduced to lowest terms, in the sense that the greatest common divisor of the numerator and the denominator should be 1. So, for instance, the ratio of 15 to -9 is -5/3. Equivalently, one can regard a ratio as consisting of a sign -- negative or non-negative, perhaps -- and two natural numbers, of which the second, the denominator, is non-zero.
There are two limitations to the use of ratios. One is that a number of functions that are commonly used in scientific applications -- trigonometric functions, logarithms, exponentiation to fractional powers (including square roots) -- yield irrational numbers as values even when applied to rational arguments. For this reason, they are simply not implemented as operations on ratios as an abstract data type; in practice, when applying such an operation, one converts the ratio to an approximately equal real, performs the operation on the real, and (perhaps) converts the result back to an approximately equal ratio, abandoning the attempt to obtain an exact result.
The other limitation is that in the course of a long computation on ratios,
the numerators and denominators of the fractions expressing the exact
results sometimes tend to get very large, much larger than
MaxInt in many cases. Since we have a bignum package, this
means only that that computations become very slow, but the attempt to
preserve exact results can become more trouble that it is worth.
Here's a repertoire of operations on ratios:
make
Input: s, a sign, and n and d, both
natural numbers.
Output: result, a ratio.
Precondition: d is not 0.
Postcondition: result is the ratio with sign s,
numerator n, and denominator d.
negate
Input: negand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: The sum of negand and result is
0/1.
absolute-value
Input: operand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the magnitude of
operand, that is, its distance (in either direction) from
0/1.
negative
Input: operand, a ratio.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand
is less than 0/1, false if it is greater or if it is
0/1.
zero
Input: operand, a ratio.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand
is 0/1, false if it is any other integer.
positive
Input: operand, a ratio.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand
is greater than 0/1, false if it is less or if it is
0/1.
add
Inputs: augend and addend, both ratios.
Output: sum, a ratio.
Preconditions: none.
Postcondition: sum is the sum of augend and
addend.
subtract
Inputs: minuend and subtrahend, both ratios.
Output: difference, a ratio.
Preconditions: none.
Postcondition: minuend is the sum of difference
and subtrahend.
multiply
Inputs: multiplicand and multiplier, both
ratios.
Output: product, a ratio.
Preconditions: none.
Postcondition: product is the product of
multiplicand and multiplier.
divide
Inputs: dividend and divisor, both ratios.
Output: quotient, a ratio.
Precondition: divisor is not 0/1.
Postconditions: dividend is the product of
quotient and divisor.
raise
Inputs: base, a ratio, and exponent, an
integer.
Output: power, a ratio.
Preconditions: Either base is not 0/1 or
exponent is not negative.
Postconditions: power is the result of raising
base to the power of exponent.
If base is 0/1 and exponent is 0,
power is 1/1.
twice
Input: operand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the product of operand
and 2.
half
Input: operand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: operand is the product of result
and 2.
square
Input: operand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the result of raising
operand to the power 2.
cube
Input: operand, a ratio.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the result of raising
operand to the power 3.
reciprocal
Input: operand, a ratio.
Output: result, a ratio.
Precondition: operand is not 0/1.
Postcondition: The product of operand and result
is 1/1.
equal
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if the operands are the
same ratio, false if they are different ratios.
unequal
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if the operands are
different ratios, false if they are the same ratio.
less
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if
left-operand is less than right-operand,
false if it is greater than right-operand or if both
operands are the same ratio.
less-or-equal
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if
left-operand is less than right-operand or if
both operands are the same ratio, false if
left-operand is greater than right-operand.
greater
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if
left-operand is greater than right-operand,
false if it is less than right-operand or if both
operands are the same ratio.
greater-or-equal
Inputs: left-operand and right-operand, both
ratios.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if
left-operand is greater than right-operand or if
both operands are the same ratio, false if
left-operand is less than right-operand.
major
Inputs: left-operand and right-operand, both
ratios.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the greater of the operands.
minor
Inputs: left-operand and right-operand, both
ratios.
Output: result, a ratio.
Preconditions: none.
Postcondition: result is the lesser of the operands.
read
Input: source, a data source (e.g., a file, the keyboard, a
device).
Outputs: legend, a ratio, and success, a
Boolean.
Preconditions: none.
Postcondition: Either some representation of a ratio has been extracted
from source, legend is that ratio, and
success is true, value, or an input error of some kind
has occurred and success is false.
write
Inputs: target, a data sink (e.g., a file, a window, a
device), and scribend, a ratio.
Outputs: none.
Preconditions: none.
Postcondition: A representation of scribend has been appended
to target.
Ratios module in HP PascalNaturals module.
In order to provide an opaque data type, the Ratio will
actually be defined as a pointer to a record containing the sign,
numerator, and denominator in the ratio. This makes it necessary to
include a DeallocateRatio procedure, to recycle storage that
is dynamically allocated for ratios. Since ratios will have ``pointer
semantics'' with respect to assignment, I have also supplied an
AssignRatio procedure that builds a copy of the ratio instead
of simply copying a pointer.
{ This module defines an interface for a Ratio data type and implements it
for HP 9000 Series 700 workstations under HP-UX 9.x, using HP Pascal.
Programmer: John Stone, Grinnell College.
Original version: February 13-20, 1996.
Extensively revised: November 13, 1996.
Reading a fraction with denominator 0 now fails: November 15, 1996.
}
$heap_dispose on$
module Ratios;
$search 'naturals.o, bidirectional-lists.o, natural-elements.o'$
import
Naturals;
export
type
Signum = (Negative, Nonnegative);
Ratio = ^RatioStructure;
{ The MakeRatio function returns the ratio of two natural numbers, with
the specified sign (except that the sign of a zero ratio is always
non-negative. }
function MakeRatio (S: Signum; N, D: Natural): Ratio;
{ The NegateRatio function returns the negative, the additive inverse,
of a given ratio. }
function NegateRatio (Negand: Ratio): Ratio;
{ The AbsoluteValueOfRatio function returns the absolute value of a given
ratio. }
function AbsoluteValueOfRatio (Operand: Ratio): Ratio;
{ The NegativeRatio function determines whether a given ratio is
strictly Negative -- less than zero. }
function NegativeRatio (Operand: Ratio): Boolean;
{ The ZeroRatio function determines whether a given ratio is 0/1,
returning True if it is and False if it is not. }
function ZeroRatio (Operand: Ratio): Boolean;
{ The PositiveRatio function determines whether a given ratio is
strictly positive -- greater than zero. }
function PositiveRatio (Operand: Ratio): Boolean;
{ The AddRatio function adds any two ratios and returns their sum. }
function AddRatio (Augend, Addend: Ratio): Ratio;
{ The SubtractRatio function subtracts one ratio (the subtrahend) from
another (the minuend) and returns their difference. }
function SubtractRatio (Minuend, Subtrahend: Ratio): Ratio;
{ The MultiplyRatio function multiplies one ratio (the multiplicand) by
another (the multiplier) and returns their product. }
function MultiplyRatio (Multiplicand, Multiplier: Ratio): Ratio;
{ The DivideRatio function divides one ratio (the dividend) by
another (the divisor) and returns the quotient as a ratio. It
presupposes that the divisor is not zero. }
function DivideRatio (Dividend, Divisor: Ratio): Ratio;
{ The RaiseRatio function raises a ratio (the base) to the power
specified by an integer (the exponent) and returns the result as
a ratio. It returns 1/1 whenever the exponent is zero, even if the
base is also zero. }
function RaiseRatio (Base: Ratio; Exponent: Integer): Ratio;
{ Given a ratio, the TwiceRatio function computes and returns its double
-- that is, the ratio that is twice as large. }
function TwiceRatio (Operand: Ratio): Ratio;
{ Given a ratio, the HalfRatio function computes and returns its half. }
function HalfRatio (Operand: Ratio): Ratio;
{ Given a ratio, the SquareRatio function computes and returns its
square. }
function SquareRatio (Operand: Ratio): Ratio;
{ Given a ratio, the CubeRatio function computes and returns its cube. }
function CubeRatio (Operand: Ratio): Ratio;
{ Given a non-zero ratio, the ReciprocalOfRatio function computes and
returns its reciprocal -- its multiplicative inverse. }
function ReciprocalOfRatio (Operand: Ratio): Ratio;
{ The EqualRatios function determines whether its arguments are
arithmetically equal -- not necessarily identical as storage
structures, but equal in value. }
function EqualRatios (LeftOperand, RightOperand: Ratio): Boolean;
{ The UnequalRatios function determines whether the first of its
arguments differs in value from its second -- not whether they differ
as storage structures, but whether their arithmetical values differ. }
function UnequalRatios (LeftOperand, RightOperand: Ratio): Boolean;
{ The LessRatio function determines whether the first of its arguments is
numerically less than the second. }
function LessRatio (LeftOperand, RightOperand: Ratio): Boolean;
{ The LessOrEqualRatio function determines whether the first of its
arguments is arithmetically greater than the second, returning False
if it is and True if it is not. (In other words, it returns True if
its first argument is arithmetically less than or equal to its
second.) }
function LessOrEqualRatio (LeftOperand, RightOperand: Ratio): Boolean;
{ The GreaterRatio function determines whether the first of its
arguments is arithmetically greater than the second. }
function GreaterRatio (LeftOperand, RightOperand: Ratio): Boolean;
{ The GreaterOrEqualRatio function determines whether the first of its
arguments is arithmetically less than the second, returning False if it
is and True if it is not. (In other words, it returns True if its
first argument is arithmetically greater than or equal to its
second.) }
function GreaterOrEqualRatio (LeftOperand, RightOperand: Ratio): Boolean;
{ The MajorRatio function returns the greater of its two arguments; if
they are equal, it returns the first of the two. }
function MajorRatio (LeftOperand, RightOperand: Ratio): Ratio;
{ The MinorRatio function returns the lesser of its two arguments; if they
are equal, it returns the first of the two. }
function MinorRatio (LeftOperand, RightOperand: Ratio): Ratio;
{ The ReadRatio procedure attempts to collect, from a specified text file,
a sequence of characters consisting of zero or more whitespace
characters, an optional sign (+ or -), one or more decimal digits, and,
optionally, a slash and one or more further decimal digits. If
successful, it computes the ratio expressed by this numeral and stores
it in the parameter Legend. The parameter Success indicates whether
the attempt succeeded; if Success is False, the value of Legend is
undefined. }
procedure ReadRatio (var Source: Text; var Legend: Ratio;
var Success: Boolean);
{ The WriteRatio procedure writes a base-ten fraction for a given ratio
to a specified Text file: first, if the ratio is negative, a minus
sign; then the numerator, with no leading zeroes or spaces (but the
single digit '0' is written if the given ratio is 0/1); then a slash;
and finally the denominator, again with no leading zeroes or spaces.
It presupposes that the Text file has already been opened for output. }
procedure WriteRatio (var Target: Text; Scribend: Ratio);
{ The AssignRatio procedure copies a given Ratio into a variable
location. }
procedure AssignRatio (var Target: Ratio; Source: Ratio);
{ Given any natural number, the NaturalToRatio function constructs
and returns a ratio of equal value. }
function NaturalToRatio (Operand: Natural): Ratio;
{ Given any (Pascal) integer, the PascalIntegerToRatio function
constructs and returns a ratio of equal value. }
function PascalIntegerToRatio (Operand: Integer): Ratio;
{ Given any (Pascal) real, the PascalRealToRatio function constructs and
returns a ratio of equal value. }
function PascalRealToRatio (Operand: Real): Ratio;
{ Given any non-negative ratio, the RoundRatioToNatural function returns
the natural number of most nearly equal value. If the ratio is
exactly halfway between two natural numbers, this function returns
whichever of them is even. }
function RoundRatioToNatural (Operand: Ratio): Natural;
{ Given any ratio, the RoundRatioToPascalInteger function returns the
integer of most nearly equal value. If the ratio is exactly halfway
between two integers, this function returns whichever of them is
even. This function presupposes that the value of its argument is
neither greater than MaxInt nor less than MinInt. }
function RoundRatioToPascalInteger (Operand: Ratio): Integer;
{ Given any ratio, the RatioToPascalReal function returns the Pascal real
of most nearly equal value. }
function RatioToPascalReal (Operand: Ratio): Real;
{ The DeallocateRatio procedure frees all of the storage allocated for
a given ratio and changes the value of its argument to nil. It
presupposes that a ratio has been stored in R and not previously
deallocated. }
procedure DeallocateRatio (var R: Ratio);
implement
import
StdErr;
{ The following constants are more or less arbitrary integers
signifying various kinds of exceptions that can occur within this
module. }
const
FirstExceptionCode = 1;
UninitializedRatioException = 1;
MakeRatioException = 2;
InvalidRatioException = 3;
DivideRatioException = 4;
RaiseRatioException = 5;
ReciprocalOfRatioException = 6;
RatioToNaturalException = 7;
RatioToPascalIntegerException = 8;
ExceptionException = 9;
LastExceptionCode = ExceptionException;
{ The structure used to represent a ratio consists of a sign, a
numerator, and a denominator. The numerator and the denominator
are natural numbers, and it is an invariant of this module that
in every ratio that is released, the numerator and denominator
are relatively prime. Also, the denominator is never zero. }
Debug = True;
{ True during debugging, False (for greater speed) when the
module is released }
type
RatioStructure = record
Sign: Signum;
Numerator: Natural;
Denominator: Natural
end;
{ The RatioExceptionHandler procedure is invoked whenever one of the
preconditions for the successful execution of a procedure is found to
be false. It prints out an appropriate explanation of the exception
just before the program is halted. }
procedure RatioExceptionHandler (ExceptionCode: Integer);
begin
if (ExceptionCode < FirstExceptionCode) or
(LastExceptionCode < ExceptionCode) then
ExceptionCode := ExceptionException;
Write (StdErr, 'Exception #', ExceptionCode : 1,
' in module Ratios: ');
case ExceptionCode of
UninitializedRatioException:
WriteLn (StdErr, 'uninitialized ratio provided as argument');
MakeRatioException:
WriteLn (StdErr, 'attempt to construct a ratio with denominator ',
'zero in function MakeRatio');
InvalidRatioException:
WriteLn (StdErr, 'attempt to return an incorrectly constructed ',
'ratio');
DivideRatioException:
WriteLn (StdErr, 'division by zero attempted in function ',
'DivideRatio');
RaiseRatioException:
WriteLn (StdErr, 'attempt to raise zero to a negative power in ',
'function RaiseRatio');
ReciprocalOfRatioException:
WriteLn (StdErr, 'zero argument to function ReciprocalOfRatio');
RatioToNaturalException:
WriteLn (StdErr, 'Negative argument to function ',
'RoundRatioToNatural');
RatioToPascalIntegerException:
WriteLn (StdErr, 'argument out of range in function ',
'RoundRatioToPascalInteger');
ExceptionException:
WriteLn (StdErr, 'argument out of range in procedure ',
'RatioExceptionHandler.')
end
end;
{ The GCD function finds and returns the greatest common divisor of any
two natural numbers, using Euclid's algorithm. If either of its
arguments is zero, the function returns a copy of the other argument. }
function GCD (LeftOperand, RightOperand: Natural): Natural;
var
Primus, Secundus: Natural;
{ initially copies of LeftOperand and RightOperand, but decreasing
towards the greatest common divisor and zero, respectively }
Rest: Natural;
{ the remainder after a trial division }
begin
AssignNatural (Primus, LeftOperand);
AssignNatural (Secundus, RightOperand);
while not ZeroNatural (Secundus) do begin
Rest := RemainderNatural (Primus, Secundus);
DeallocateNatural (Primus);
Primus := Secundus;
Secundus := Rest
end;
DeallocateNatural (Secundus);
GCD := Primus
end;
{ The ValidRatio function determines whether its argument is valid as
a ratio. (A valid ratio has a non-zero denominator and its numerator
and denominator are relatively prime.) }
function ValidRatio (Operand: Ratio): Boolean;
var
Common: Natural;
{ the greatest common divisor of the ratio's numerator and
denominator }
One: Natural;
{ the natural number 1 }
begin
if Operand = nil then
ValidRatio := False
else if ZeroNatural (Operand^.Denominator) then
ValidRatio := False
else begin
Common := GCD (Operand^.Numerator, Operand^.Denominator);
One := PascalIntegerToNatural (1);
ValidRatio := EqualNaturals (Common, One);
DeallocateNatural (Common);
DeallocateNatural (One)
end
end;
{ The BuildRatio function allocates storage for a ratio and initializes
its fields with the specified values, allocating fresh storage for
the numerator and denominator if the value of the parameter ut
(``use or throw out'') is False, but using the given storage if it is
True. This function presupposes that D is non-zero and that N and D
are relatively prime. }
function BuildRatio (S: Signum; N: Natural; D: Natural; UT: Boolean):
Ratio;
var
Result: Ratio;
{ a pointer to the newly allocated record }
begin
New (Result);
if ZeroNatural (N) then
Result^.Sign := Nonnegative
else
Result^.Sign := S;
if UT then begin
Result^.Numerator := N;
Result^.Denominator := D
end
else begin
AssignNatural (Result^.Numerator, N);
AssignNatural (Result^.Denominator, D)
end;
BuildRatio := Result
end;
{ The BuildAndReduce function constructs and returns a ratio having
the specified sign and an absolute value is equal to the quotient of N
and D. Unlike BuildRatio, it does not assume that N and D are
relatively prime, though it does presuppose that D is not zero. }
function BuildAndReduce (S: Signum; N: Natural; D: Natural;
UT: Boolean): Ratio;
var
Common: Natural;
{ the greatest common divisor of N and D }
One: Natural;
{ 1, as a Natural number }
begin
Common := GCD (N, D);
One := PascalIntegerToNatural (1);
if EqualNaturals (Common, One) then
BuildAndReduce := BuildRatio (S, N, D, UT)
else begin
BuildAndReduce := BuildRatio (S, QuotientNatural (N, Common),
QuotientNatural (D, Common), True);
if UT then begin
DeallocateNatural (N);
DeallocateNatural (D)
end
end;
DeallocateNatural (Common);
DeallocateNatural (One)
end;
{ The Opposite function returns the sign opposite to any given sign. }
function Opposite (S: Signum): Signum;
begin
case S of
Negative:
Opposite := Nonnegative;
Nonnegative:
Opposite := Negative
end
end;
function MakeRatio (S: Signum; N, D: Natural): Ratio;
var
Result: Ratio;
begin
Assert (not ZeroNatural (D), MakeRatioException, RatioExceptionHandler);
Result := BuildAndReduce (S, N, D, False);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
MakeRatio := Result
end;
function NegateRatio (Negand: Ratio): Ratio;
var
Result: Ratio;
begin
Assert (Negand <> nil, UninitializedRatioException,
RatioExceptionHandler);
if (Negand^.Sign = Negative) or ZeroNatural (Negand^.Numerator) then
Result := BuildRatio (Nonnegative, Negand^.Numerator,
Negand^.Denominator, False)
else
Result := BuildRatio (Negative, Negand^.Numerator,
Negand^.Denominator, False);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
NegateRatio := Result
end;
function AbsoluteValueOfRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
Result := BuildRatio (Nonnegative, Operand^.Numerator,
Operand^.Denominator, False);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
AbsoluteValueOfRatio := Result
end;
function NegativeRatio (Operand: Ratio): Boolean;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
NegativeRatio := (Operand^.Sign = Negative)
end;
function ZeroRatio (Operand: Ratio): Boolean;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
ZeroRatio := ZeroNatural (Operand^.Numerator)
end;
function PositiveRatio (Operand: Ratio): Boolean;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
PositiveRatio := (Operand^.Sign = Nonnegative) and
not ZeroNatural (Operand^.Numerator)
end;
function AddRatio (Augend, Addend: Ratio): Ratio;
var
AD, BC, BD: Natural;
{ a/b + c/d = (ad + bc) / bd }
Result: Ratio;
begin
Assert ((Augend <> nil) and (Addend <> nil),
UninitializedRatioException,
RatioExceptionHandler);
AD := MultiplyNatural (Augend^.Numerator, Addend^.Denominator);
BC := MultiplyNatural (Augend^.Denominator, Addend^.Numerator);
BD := MultiplyNatural (Augend^.Denominator, Addend^.Denominator);
if Augend^.Sign = Addend^.Sign then
Result := BuildAndReduce (Augend^.Sign, AddNatural (AD, BC), BD,
True)
else if LessNatural (AD, BC) then
Result := BuildAndReduce (Addend^.Sign, SubtractNatural (BC, AD),
BD, True)
else if LessNatural (BC, AD) then
Result := BuildAndReduce (Augend^.Sign, SubtractNatural (AD, BC),
BD, True)
else begin
DeallocateNatural (BD);
Result := BuildRatio (Nonnegative, PascalIntegerToNatural (0),
PascalIntegerToNatural (1), True)
end;
DeallocateNatural (AD);
DeallocateNatural (BC);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
AddRatio := Result
end;
function SubtractRatio (Minuend, Subtrahend: Ratio): Ratio;
var
AD, BC, BD: Natural;
{ a/b - c/d = (ad - bc) / bd }
Result: Ratio;
begin
Assert ((Minuend <> nil) and (Subtrahend <> nil),
UninitializedRatioException,
RatioExceptionHandler);
AD := MultiplyNatural (Minuend^.Numerator, Subtrahend^.Denominator);
BC := MultiplyNatural (Minuend^.Denominator, Subtrahend^.Numerator);
BD := MultiplyNatural (Minuend^.Denominator, Subtrahend^.Denominator);
if Minuend^.Sign <> Subtrahend^.Sign then
Result := BuildAndReduce (Minuend^.Sign, AddNatural (AD, BC),
BD, True)
else if LessNatural (AD, BC) then
Result := BuildAndReduce (Opposite (Minuend^.Sign),
SubtractNatural (BC, AD), BD, True)
else if LessNatural (BC, AD) then
Result := BuildAndReduce (Minuend^.Sign,
SubtractNatural (AD, BC), BD, True)
else begin
DeallocateNatural (BD);
Result := BuildRatio (Nonnegative, PascalIntegerToNatural (0),
PascalIntegerToNatural (1), True)
end;
DeallocateNatural (AD);
DeallocateNatural (BC);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
SubtractRatio := Result
end;
function MultiplyRatio (Multiplicand, Multiplier: Ratio): Ratio;
var
Result: Ratio;
begin
Assert ((Multiplicand <> nil) and (Multiplier <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if (Multiplicand^.Sign = Multiplier^.Sign) or
ZeroNatural (Multiplicand^.Numerator) or
ZeroNatural (Multiplier^.Numerator) then
Result :=
BuildAndReduce(Nonnegative,
MultiplyNatural (Multiplicand^.Numerator,
Multiplier^.Numerator),
MultiplyNatural (Multiplicand^.Denominator,
Multiplier^.Denominator),
True)
else
Result :=
BuildAndReduce(Negative,
MultiplyNatural (Multiplicand^.Numerator,
Multiplier^.Numerator),
MultiplyNatural (Multiplicand^.Denominator,
Multiplier^.Denominator),
True);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
MultiplyRatio := Result
end;
function DivideRatio (Dividend, Divisor: Ratio): Ratio;
var
Result: Ratio;
begin
Assert ((Dividend <> nil) and (Divisor <> nil),
UninitializedRatioException,
RatioExceptionHandler);
Assert (not ZeroNatural (Divisor^.Numerator), DivideRatioException,
RatioExceptionHandler);
if (Dividend^.Sign = Divisor^.Sign) or
ZeroNatural (Dividend^.Numerator) then
Result :=
BuildAndReduce(Nonnegative,
MultiplyNatural (Dividend^.Numerator,
Divisor^.Denominator),
MultiplyNatural (Dividend^.Denominator,
Divisor^.Numerator),
True)
else
Result :=
BuildAndReduce(Negative,
MultiplyNatural (Dividend^.Numerator,
Divisor^.Denominator),
MultiplyNatural (Dividend ^.Denominator,
Divisor^.Numerator),
True);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
DivideRatio := Result
end;
function RaiseRatio (Base: Ratio; Exponent: Integer): Ratio;
var
S: Signum;
{ the sign of the result }
Temporary: Natural;
{ temporary storage for an intermediate value in the construction
of NaturalExponent }
NaturalExponent: Natural;
{ the absolute value of Exponent, as a natural number }
Result: Ratio;
begin
Assert (Base <> nil, UninitializedRatioException,
RatioExceptionHandler);
Assert (not ZeroRatio (Base) or (0 <= Exponent), RaiseRatioException,
RatioExceptionHandler);
if Odd (Exponent) then
S := Base^.Sign
else
S := Nonnegative;
if Exponent = MinInt then begin
Temporary := PascalIntegerToNatural (MaxInt);
NaturalExponent := SuccessorOfNatural (Temporary);
DeallocateNatural (Temporary)
end
else
NaturalExponent := PascalIntegerToNatural (Abs (Exponent));
if Exponent < 0 then
Result :=
BuildRatio (S, RaiseNatural (Base^.Denominator, NaturalExponent),
RaiseNatural (Base^.Numerator, NaturalExponent),
True)
else
Result :=
BuildRatio (S, RaiseNatural (Base^.Numerator, NaturalExponent),
RaiseNatural (Base^.Denominator, NaturalExponent),
True);
DeallocateNatural (NaturalExponent);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
RaiseRatio := Result
end;
function TwiceRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
{ the newly allocated ratio, twice as large as the given one }
Two: Natural;
{ the natural number 2 }
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
New (Result);
Result^.Sign := Operand^.Sign;
if EvenNatural (Operand^.Denominator) then begin
AssignNatural (Result^.Numerator, Operand^.Numerator);
Two := PascalIntegerToNatural (2);
Result^.Denominator := QuotientNatural (Operand^.Denominator, Two);
DeallocateNatural (Two)
end
else begin
Result^.Numerator := TwiceNatural (Operand^.Numerator);
AssignNatural (Result^.Denominator, Operand^.Denominator)
end;
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
TwiceRatio := Result
end;
function HalfRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
{ the newly allocated ratio, half as large as the given one }
Two: Natural;
{ the natural number 2 }
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
New (Result);
Result^.Sign := Operand^.Sign;
if EvenNatural (Operand^.Numerator) then begin
Two := PascalIntegerToNatural (2);
Result^.Numerator := QuotientNatural (Operand^.Numerator, Two);
DeallocateNatural (Two);
AssignNatural (Result^.Denominator, Operand^.Denominator)
end
else begin
AssignNatural (Result^.Numerator, Operand^.Numerator);
Result^.Denominator := TwiceNatural (Operand^.Denominator)
end;
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
HalfRatio := Result
end;
function SquareRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
Result := BuildRatio (Nonnegative,
SquareNatural (Operand^.Numerator),
SquareNatural (Operand^.Denominator), True);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
SquareRatio := Result
end;
function CubeRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
Result := BuildRatio (Operand^.Sign,
CubeNatural (Operand^.Numerator),
CubeNatural (Operand^.Denominator), True);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
CubeRatio := Result
end;
function ReciprocalOfRatio (Operand: Ratio): Ratio;
var
Result: Ratio;
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
Assert (not ZeroNatural (Operand^.Numerator),
ReciprocalOfRatioException,
RatioExceptionHandler);
Result := BuildRatio (Operand^.Sign, Operand^.Denominator,
Operand^.Numerator, False);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
ReciprocalOfRatio := Result
end;
function EqualRatios (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if (LeftOperand^.Sign = RightOperand^.Sign) then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
EqualRatios := EqualNaturals (AD, BC);
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
EqualRatios := False
end;
function UnequalRatios (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if (LeftOperand^.Sign = RightOperand^.Sign) then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
UnequalRatios := UnequalNaturals (AD, BC);
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
UnequalRatios := True
end;
function LessRatio (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if LeftOperand^.Sign = RightOperand^.Sign then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
case LeftOperand^.Sign of
Negative:
LessRatio := LessNatural (BC, AD);
Nonnegative:
LessRatio := LessNatural (AD, BC);
end;
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
LessRatio := (LeftOperand^.Sign = Negative)
end;
function LessOrEqualRatio (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if LeftOperand^.Sign = RightOperand^.Sign then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
case LeftOperand^.Sign of
Negative:
LessOrEqualRatio := LessOrEqualNatural (BC, AD);
Nonnegative:
LessOrEqualRatio := LessOrEqualNatural (AD, BC);
end;
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
LessOrEqualRatio := (LeftOperand^.Sign = Negative)
end;
function GreaterRatio (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if LeftOperand^.Sign = RightOperand^.Sign then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
case LeftOperand^.Sign of
Negative:
GreaterRatio := GreaterNatural (BC, AD);
Nonnegative:
GreaterRatio := GreaterNatural (AD, BC);
end;
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
GreaterRatio := (LeftOperand^.Sign = Nonnegative)
end;
function GreaterOrEqualRatio (LeftOperand, RightOperand: Ratio): Boolean;
var
AD, BC: Natural;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if LeftOperand^.Sign = RightOperand^.Sign then begin
AD := MultiplyNatural (LeftOperand^.Numerator,
RightOperand^.Denominator);
BC := MultiplyNatural (LeftOperand^.Denominator,
RightOperand^.Numerator);
case LeftOperand^.Sign of
Negative:
GreaterOrEqualRatio := GreaterOrEqualNatural (BC, AD);
Nonnegative:
GreaterOrEqualRatio := GreaterOrEqualNatural (AD, BC);
end;
DeallocateNatural (AD);
DeallocateNatural (BC)
end
else
GreaterOrEqualRatio := (LeftOperand^.Sign = Nonnegative)
end;
function MajorRatio (LeftOperand, RightOperand: Ratio): Ratio;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if GreaterOrEqualRatio (LeftOperand, RightOperand) then
MajorRatio := LeftOperand
else
MajorRatio := RightOperand
end;
function MinorRatio (LeftOperand, RightOperand: Ratio): Ratio;
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedRatioException,
RatioExceptionHandler);
if LessOrEqualRatio (LeftOperand, RightOperand) then
MinorRatio := LeftOperand
else
MinorRatio := RightOperand
end;
procedure ReadRatio (var Source: Text; var Legend: Ratio;
var Success: Boolean);
label
99;
{ early exit if a syntax error is detected }
var
S: Signum;
{ the sign of the ratio, as recovered from the source file }
N, D: Natural;
{ the numerator and denominator of the Ratio, as recovered from
the source file }
Slash: Boolean;
{ indicates whether there is a slash after the numerator,
presumably followed by an explicit denominator }
{ The SkipWhiteSpace procedure advances through a text file until
a non-whitespace character (or the end of the file) is encountered. }
procedure SkipWhiteSpace (var Source: Text);
const
Space = ' ';
var
Finished: Boolean;
{ indicates whether it is necessary to keep looking for white
space to skip }
begin
Finished := False;
while not Finished do
if EOF (Source) then
Finished := True
else if (Source^ <= Space) or (Source^ = Chr (127)) then
Get (Source)
else
Finished := True
end;
function Numeric (Ch: Char): Boolean;
begin
Numeric := ('0' <= Ch) and (Ch <= '9')
end;
begin { procedure ReadRatio }
SkipWhiteSpace (Source);
if EOF (Source) then begin
Success := False;
goto 99
end;
{ Recover the sign of the ratio. }
if Source^ = '-' then begin
S := Negative;
Get (Source);
if EOF (Source) then begin
Success := False;
goto 99
end
end
else if Source^ = '+' then begin
S := Nonnegative;
Get (Source);
if EOF (Source) then begin
Success := False;
goto 99
end
end
else
S := Nonnegative;
{ Read in the numerator. }
ReadNatural (Source, N, Success);
if not Success then
goto 99;
{ Deal with the slash, if it is present. }
if EOF (Source) then
Slash := False
else
Slash := (Source^ = '/');
if Slash then begin
{ Read in the denominator. }
Get (Source);
ReadNatural (Source, D, Success);
if ZeroNatural (D) then begin
Success := False;
DeallocateNatural (D)
end;
if not Success then begin
DeallocateNatural (N);
goto 99
end
end
else
D := PascalIntegerToNatural (1);
if ZeroNatural (N) then
S := Nonnegative;
Legend := BuildAndReduce (S, N, D, True);
if Debug then
Assert (ValidRatio (Legend), InvalidRatioException,
RatioExceptionHandler);
99:
end;
procedure WriteRatio (var Target: Text; Scribend: Ratio);
begin
Assert (Scribend <> nil, UninitializedRatioException,
RatioExceptionHandler);
if Scribend^.Sign = Negative then
Write (Target, '-');
WriteNatural (Target, Scribend^.Numerator);
Write (Target, '/');
WriteNatural (Target, Scribend^.Denominator)
end;
procedure AssignRatio (var Target: Ratio; Source: Ratio);
begin
Assert (Source <> nil, UninitializedRatioException,
RatioExceptionHandler);
New (Target);
Target^.Sign := Source^.Sign;
AssignNatural (Target^.Numerator, Source^.Numerator);
AssignNatural (Target^.Denominator, Source^.Denominator);
if Debug then
Assert (ValidRatio (Target), InvalidRatioException,
RatioExceptionHandler)
end;
function NaturalToRatio (Operand: Natural): Ratio;
var
Result: Ratio;
begin
New (Result);
Result^.Sign := Nonnegative;
AssignNatural (Result^.Numerator, Operand);
Result^.Denominator := PascalIntegerToNatural (1);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
NaturalToRatio := Result
end;
function PascalIntegerToRatio (Operand: Integer): Ratio;
var
One: Natural;
{ the natural number 1 }
S: Signum;
{ the sign of Operand, and hence of the ratio }
MaxIntAsNatural: Natural;
{ a natural number equal in value to MaxInt }
Numer: Natural;
{ the numerator of the ratio }
Result: Ratio;
begin
One := PascalIntegerToNatural (1);
if Operand = MinInt then begin
S := Negative;
MaxIntAsNatural := PascalIntegerToNatural (MaxInt);
Numer := AddNatural (MaxIntAsNatural, One);
DeallocateNatural (MaxIntAsNatural)
end
else begin
if Operand < 0 then
S := Negative
else
S := Nonnegative;
Numer := PascalIntegerToNatural (Abs (Operand))
end;
Result := BuildRatio (S, Numer, One, True);
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
PascalIntegerToRatio := Result
end;
function PascalRealToRatio (Operand: Real): Ratio;
var
S: Signum;
{ the sign of the resulting ratio }
Exponent: Integer;
{ the exponent of a power of two that must be multiplied into the
ratio to make it equal in value to the original operand }
Mantissa: Natural;
{ the value of one or more leading bits of the mantissa; ultimately,
the value of the bits of the mantissa up to and including the
rightmost one-bit }
Temporary: Natural;
{ temporary storage for a pointer to the next value of Mantissa }
Two: Natural;
{ the natural number 2 }
NaturalExponent: Natural;
{ a natural number equal in value to the absolute value of Exponent }
PowerOfTwo: Natural;
{ two to the power of NaturalExponent }
Result: Ratio;
begin
if Operand = 0.0 then
Result := BuildRatio (Nonnegative, PascalIntegerToNatural (0),
PascalIntegerToNatural (1), True)
else begin
if Operand < 0.0 then begin
S := Negative;
Operand := -Operand
end
else begin
S := Nonnegative
end;
{ Operand is now greater than zero. Now we normalize it, dividing
or multiplying it repeatedly by 2 until it is in the range from
1.0 (inclusive) to 2.0 (exclusive). }
Exponent := 0;
while 2.0 <= Operand do begin
Operand := Operand / 2;
Exponent := Exponent + 1
end;
while Operand < 1.0 do begin
Operand := Operand * 2;
Exponent := Exponent - 1
end;
{ Next, we recover the mantissa one bit at a time, starting with
the hidden bit and continuing until the operand has been reduced
to 0.0. }
Mantissa := PascalIntegerToNatural (1);
Operand := Operand - 1.0;
while Operand <> 0.0 do begin
Operand := Operand * 2;
Temporary := TwiceNatural (Mantissa);
DeallocateNatural (Mantissa);
if 1.0 <= Operand then begin
Operand := Operand - 1.0;
Mantissa := SuccessorOfNatural (Temporary);
DeallocateNatural (Temporary)
end
else
Mantissa := Temporary;
Exponent := Exponent - 1
end;
{ If the exponent is still non-negative, the ratio has the mantissa
times 2^exponent as its numerator and 1 as its denominator;
if the exponent is negative, the ratio has the mantissa as its
numerator and 2^(-exponent) as its denominator. }
Two := PascalIntegerToNatural (2);
if 0 <= Exponent then begin
NaturalExponent := PascalIntegerToNatural (Exponent);
PowerOfTwo := RaiseNatural (Two, NaturalExponent);
DeallocateNatural (NaturalExponent);
Result := BuildRatio (S, MultiplyNatural (Mantissa, PowerOfTwo),
PascalIntegerToNatural (1), True);
DeallocateNatural (PowerOfTwo);
DeallocateNatural (Mantissa)
end
else begin
NaturalExponent := PascalIntegerToNatural (-Exponent);
Result := BuildRatio (S, Mantissa,
RaiseNatural (Two, NaturalExponent), True);
DeallocateNatural (NaturalExponent)
end;
DeallocateNatural (Two)
end;
if Debug then
Assert (ValidRatio (Result), InvalidRatioException,
RatioExceptionHandler);
PascalRealToRatio := Result
end;
function RoundRatioToNatural (Operand: Ratio): Natural;
var
Quot, Rem: Natural;
{ the quotient and remainder, respectively, when the numerator of the
ratio is divided by its denominator }
TwiceRem: Natural;
{ a natural number twice as large as Rem }
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
Assert (Operand^.Sign = Nonnegative, RatioToNaturalException,
RatioExceptionHandler);
DivideNatural (Operand^.Numerator, Operand^.Denominator, Quot, Rem);
TwiceRem := TwiceNatural (Rem);
DeallocateNatural (Rem);
if LessNatural (Operand^.Denominator, TwiceRem) or
(EqualNaturals (Operand^.Denominator, TwiceRem) and
OddNatural (Quot)) then begin
RoundRatioToNatural := SuccessorOfNatural (Quot);
DeallocateNatural (Quot)
end
else
RoundRatioToNatural := Quot;
DeallocateNatural (TwiceRem)
end;
function RoundRatioToPascalInteger (Operand: Ratio): Integer;
const
ValueBitsInInteger = 31;
{ the number of bits in the representation of an integer, not
counting the sign bit }
var
OriginalSign: Signum;
{ the sign of the ratio, and hence of the integer }
Rounded: Natural;
{ the natural number nearest to the absolute value of the ratio }
BitCounter: Integer;
{ counts off the value bits in the representation of an integer }
Two: Natural;
{ the natural number 2 }
PowerOfTwo: Integer;
{ a power of two, to be added to the absolute value of the integer
to be returned }
Temporary: Natural;
{ temporary storage for a pointer to the next value of Rounded }
Result: Integer;
{ the absolute value of the integer to be returned, computed one bit
at a time }
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
OriginalSign := Operand^.Sign;
Operand^.Sign := Nonnegative;
Rounded := RoundRatioToNatural (Operand);
Operand^.Sign := OriginalSign;
BitCounter := 0;
Result := 0;
Two := PascalIntegerToNatural (2);
PowerOfTwo := 1;
while (BitCounter < ValueBitsInInteger) and
not ZeroNatural (Rounded) do begin
if OddNatural (Rounded) then
Result := Result + PowerOfTwo;
Temporary := QuotientNatural (Rounded, Two);
DeallocateNatural (Rounded);
Rounded := Temporary;
if BitCounter <> ValueBitsInInteger - 1 then
PowerOfTwo := PowerOfTwo * 2;
BitCounter := BitCounter + 1
end;
if (Result = 0) and (OriginalSign = Negative) then begin
Temporary := PredecessorOfNatural (Rounded);
DeallocateNatural (Rounded);
Rounded := Temporary;
Assert (ZeroNatural (Rounded), RatioToPascalIntegerException,
RatioExceptionHandler);
RoundRatioToPascalInteger := MinInt
end
else begin
Assert (ZeroNatural (Rounded), RatioToPascalIntegerException,
RatioExceptionHandler);
case OriginalSign of
Negative:
RoundRatioToPascalInteger := -Result;
Nonnegative:
RoundRatioToPascalInteger := Result
end
end;
DeallocateNatural (Rounded);
DeallocateNatural (Two)
end;
function RatioToPascalReal (Operand: Ratio): Real;
const
MantissaBits = 23;
{ the number of non-hidden bits in the mantissa of a Real (here an
IEEE single-precision real }
var
Exponent: Integer;
{ the exponent of a power of two, by which the mantissa must be
multiplied }
Top, Bottom: Natural;
{ originally the numerator and denominator of the ratio, subsequently
shifted to normalize the fraction }
Temporary: Natural;
{ temporary storage for the next value of some variable }
Mantissa: Real;
{ the value of the mantissa of the real number, constructed bit by
bit }
PowerOfTwo: Real;
{ a power of two, to be added to the mantissa if the next bit of
that mantissa should be turned on }
BitNumber: Integer;
{ counts off the bits of the mantissa as they are generated }
Result: Real;
{ initially, the completed mantissa of the real number to be
returned; subsequently scaled to reflect the exponent }
Counter: Integer;
{ counts off the multiplications or divisions needed to scale the
result to the proper size }
begin
Assert (Operand <> nil, UninitializedRatioException,
RatioExceptionHandler);
if ZeroNatural (Operand^.Numerator) then
RatioToPascalReal := 0.0
else begin
Exponent := 0;
AssignNatural (Top, Operand^.Numerator);
AssignNatural (Bottom, Operand^.Denominator);
while LessNatural (Bottom, Top) do begin
Temporary := TwiceNatural (Bottom);
DeallocateNatural (Bottom);
Bottom := Temporary;
Exponent := Exponent + 1
end;
while LessNatural (Top, Bottom) do begin
Temporary := TwiceNatural (Top);
DeallocateNatural (Top);
Top := Temporary;
Exponent := Exponent - 1
end;
Mantissa := 1.0;
Temporary := SubtractNatural (Top, Bottom);
DeallocateNatural (Top);
Top := TwiceNatural (Temporary);
DeallocateNatural (Temporary);
PowerOfTwo := 1.0;
BitNumber := 1;
while BitNumber <= MantissaBits do begin
PowerOfTwo := PowerOfTwo / 2;
if GreaterOrEqualNatural (Top, Bottom) then begin
Temporary := SubtractNatural (Top, Bottom);
DeallocateNatural (Top);
Mantissa := Mantissa + PowerOfTwo;
Top := TwiceNatural (Temporary);
DeallocateNatural (Temporary)
end
else begin
Temporary := TwiceNatural (Top);
DeallocateNatural (Top);
Top := Temporary
end;
BitNumber := Bitnumber + 1
end;
if GreaterOrEqualNatural (Top, Bottom) then
Mantissa := Mantissa + PowerOfTwo;
DeallocateNatural (Top);
DeallocateNatural (Bottom);
Result := Mantissa;
for Counter := 1 to Exponent do
Result := Result * 2;
for Counter := 1 to -Exponent do
Result := Result / 2;
if Operand^.Sign = Negative then
RatioToPascalReal := -Result
else
RatioToPascalReal := Result
end
end;
procedure DeallocateRatio (var R: Ratio);
begin
Assert (R <> nil, UninitializedRatioException, RatioExceptionHandler);
DeallocateNatural (R^.Numerator);
DeallocateNatural (R^.Denominator);
Dispose (R);
R := nil
end;
end.