BigAdd:
PUBLIC
PROC [in1, in2: BigCARD]
RETURNS [out: BigCARD] ~ {
smaller: BigCARD;
addResults: CARD; carry: CARDINAL ← 0;
IF in1.size < in2.size THEN {smaller ← in1; out ← in2} ELSE {smaller ← in2; out ← in1};
out ← BigCopy[out];
IF (out.size = 0) OR (smaller.size = 0) THEN RETURN;
FOR index:
CARDINAL
IN [0..smaller.size)
DO
addResults ← LONG[out.contents[index]] + LONG[smaller.contents[index]] + carry;
out.contents[index] ← Basics.LowHalf[addResults]; carry ← Basics.HighHalf[addResults];
ENDLOOP;
FOR index:
CARDINAL
IN [smaller.size..out.size)
DO
addResults ← LONG[out.contents[index]] + carry;
out.contents[index] ← Basics.LowHalf[addResults]; carry ← Basics.HighHalf[addResults];
ENDLOOP;
IF carry > 0
THEN {
IF out.size >= out.contents.max THEN out ← BigCopy[out]; --Expand `out' if necessary
out.contents[out.size] ← carry; out.size ← out.size + 1;
};
};
BigSubtract:
PUBLIC
PROC [large, small: BigCARD, reuse:
BOOL ←
FALSE]
RETURNS [out: BigCARD] ~ {
borrow, subResults: CARD ← 0;
IF large.size < small.size THEN ERROR BigFail[$NegativeResult];
IF reuse THEN out ← large ELSE out ← BigCopy[large];
In abuse of type, borrow is conceptually an INT in what follows.
FOR index:
CARDINAL
IN [0..small.size)
DO
subResults ← LONG[out.contents[index]] - LONG[small.contents[index]] + borrow;
out.contents[index] ← Basics.LowHalf[subResults];
--The LONG and LOOPHOLEs below extend the sign of borrow.
borrow ← LOOPHOLE[LONG[LOOPHOLE[Basics.HighHalf[subResults], INTEGER]], CARD];
ENDLOOP;
FOR index:
CARDINAL
IN [small.size..out.size)
DO
subResults ← LONG[out.contents[index]] + borrow;
out.contents[index] ← Basics.LowHalf[subResults];
borrow ← LOOPHOLE[LONG[LOOPHOLE[Basics.HighHalf[subResults], INTEGER]], CARD];
ENDLOOP;
out ← StripLeadingZeros[out];
};
BigMultiply:
PUBLIC
PROC [in1, in2: BigCARD]
RETURNS [out: BigCARD] ~ {
carry: CARDINAL ← 0;
IF BigZero[in1] OR BigZero[in2] THEN RETURN;
out.size ← in1.size + in2.size;
out.contents ← NEW[BigCARDRec[out.size]];
FOR index1:
CARDINAL
IN [0..in1.size)
DO
FOR index2:
CARDINAL
IN [0..in2.size)
DO
product: CARD ← Basics.LongMult[in1.contents[index1], in2.contents[index2]]
+ LONG[out.contents[index1+index2]]+carry;
out.contents[index1+index2] ← Basics.LowHalf[product];
carry ← Basics.HighHalf[product];
ENDLOOP;
out.contents[index1+in2.size] ← carry; carry ← 0;
ENDLOOP;
out ← StripLeadingZeros[out];
};
BigDivMod:
PUBLIC
PROC [num, den: BigCARD, reuse:
BOOL ←
FALSE]
RETURNS [quo, rem: BigCARD] ~ {
highDen, nextDen: CARDINAL;
smallNum, readyToShift: CARD;
carry, subtract, borrow, multResults, subResults, addResults: CARD;
guess, normalize, remainder: CARDINAL;
oldNumSize: CARDINAL ← num.size;
leftShiftedDigit: Basics.LongNumber ← [lc[0]];
IF den.size=0 THEN ERROR BigFail[$DivideByZero];
IF den.size=1
THEN {
[quo, remainder] ← DivideByDigit[num, den.contents[0], reuse];
rem ← BigFromSmall[remainder];
RETURN;
};
IF NOT reuse THEN num ← BigCopy[num];
IF den.size > num.size
THEN {rem ← num;
RETURN};
normalize ← den.contents[den.size - 1];
SELECT normalize
FROM
0 => ERROR;
>= LAST[CARDINAL]/2 => normalize ← 1;
ENDCASE => {
normalize ← Basics.LongDiv[lastPlus, normalize+1];
num ← MultiplyByDigit[num, normalize, TRUE];
};
IF num.size = oldNumSize
THEN {
IF num.size >= num.contents.max THEN num ← BigCopy[num];
num.contents[num.size] ← 0; num.size ← num.size + 1;
};
IF normalize # 1 THEN den ← MultiplyByDigit[den, normalize, reuse];
highDen ← den.contents[den.size - 1];
nextDen ← den.contents[den.size - 2];
quo.size ← num.size - den.size;
quo.contents ← NEW[BigCARDRec[quo.size]];
FOR quoIndex:
CARDINAL
DECREASING
IN [0..quo.size)
DO
Try to guess the quotient using the leading two digits of `num' and the first digit of `den'.
leftShiftedDigit.hi ← num.contents[quoIndex + den.size];
smallNum ← leftShiftedDigit.lc + num.contents[quoIndex + den.size - 1];
guess ← IF highDen = leftShiftedDigit.hi THEN 177777B ELSE Basics.LongDiv[smallNum, highDen];
Adjust the guess by using one more digit each of `num' and `den'.
WHILE
TRUE
DO
readyToShift ← smallNum - Basics.LongMult[guess, highDen];
IF readyToShift >= 200000B THEN EXIT;
leftShiftedDigit.hi ← readyToShift;
IF leftShiftedDigit.lc+num.contents[quoIndex + den.size - 2]
>= Basics.LongMult[guess, nextDen] THEN EXIT;
guess ← guess - 1;
ENDLOOP;
Test the guess with the whole of `den'. This is almost always correct, so den * guess is actually subtracted from `num'.
carry ← borrow ← 0;
FOR denIndex:
CARDINAL
IN [0..den.size)
DO
multResults ← Basics.LongMult[den.contents[denIndex], guess] + carry;
carry ← Basics.HighHalf[multResults]; subtract ← Basics.LowHalf[multResults];
Borrow is treated as an INT, and sign extended with LOOPHOLEs below.
subResults ← LONG[num.contents[quoIndex + denIndex]] - subtract + borrow;
num.contents[quoIndex + denIndex] ← Basics.LowHalf[subResults];
borrow ← LOOPHOLE[LONG[LOOPHOLE[Basics.HighHalf[subResults], INTEGER]], CARD];
ENDLOOP;
In rare cases guess is off by one, so `den' is added back to `num'.
IF carry - borrow > num.contents[quoIndex + den.size]
THEN {
carry ← 0;
FOR denIndex:
CARDINAL
IN [0..den.size)
DO
addResults ← LONG[den.contents[denIndex]]
+ num.contents[quoIndex + denIndex] + carry;
carry ← Basics.HighHalf[addResults];
num.contents[quoIndex + denIndex] ← Basics.LowHalf[addResults];
ENDLOOP;
guess ← guess - 1;
};
quo.contents[quoIndex] ← guess;
ENDLOOP;
quo ← StripLeadingZeros[quo];
num.size ← den.size;
[rem, remainder] ← DivideByDigit[num, normalize, TRUE];
};