home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Merciful 3
/
Merciful_Release_3.bin
/
software
/
e
/
excalcv1.2reg.lha
/
ExCalcV1.2
/
Source
/
ExIntegers.mod
< prev
next >
Wrap
Text File
|
1995-10-07
|
14KB
|
576 lines
MODULE ExIntegers;
(* Some Functions to perform bit manipulation on ExNumbers.
This module deals with integral ExNumbers in the range
from -5.9863E51 to 5.9863E51. Any numbers outside this
range are represented with the maximum (or minimum)
ExNumber from this range.
*)
IMPORT io, Cnv := Conversions, Str := Strings, X := ExNumbers,
XM := ExMathLib0, SYSTEM;
TYPE
BaseType * = SHORTINT;
CONST
MaxBase2Bits = 172; (* ln(9.99E51) / ln(2) *)
LogicalSize = MaxBase2Bits DIV 16;
Left = FALSE;
Right = TRUE;
TYPE
LogicalType = ARRAY LogicalSize+1 OF SET;
LogicalProc = PROCEDURE(a,b: SET) : SET;
ExNumbProc = PROCEDURE(VAR a: X.ExNumType; b,c: X.ExNumType);
VAR
LogZero : LogicalType; (* All bits cleared or 0 *)
MaxNumber : X.ExNumType; (* 2 ** MaxBase2Bits - 1 *)
MinNumber : X.ExNumType; (* -2 ** MaxBase2Bits + 1 *)
Two : X.ExNumType; (* The value "2" *)
Cnt : INTEGER;
(*--------------------------------------*)
(* Local bit manipulations functions. *)
PROCEDURE And (op1, op2 : SET) : SET;
BEGIN
RETURN op1 * op2;
END And;
PROCEDURE AndNot (op1, op2 : SET) : SET;
BEGIN
RETURN op1 - op2;
END AndNot;
PROCEDURE Or (op1, op2 : SET) : SET;
BEGIN
RETURN op1 + op2;
END Or;
PROCEDURE Xor (op1, op2 : SET) : SET;
BEGIN
RETURN op1 / op2;
END Xor;
(*--------------------------------------*)
(* Miscellaneous local procedures *)
PROCEDURE Max (x, y : INTEGER) : INTEGER;
BEGIN
IF x > y THEN
RETURN x;
ELSE
RETURN y;
END;
END Max;
PROCEDURE ConstrainExNum (VAR Number : X.ExNumType);
(* Limit Number to be within MinNumber to MaxNumber and
eliminate any fractional portions. *)
BEGIN
X.ExMin(Number, MaxNumber, Number);
X.ExMax(Number, MinNumber, Number);
X.ExTrunc(Number);
END ConstrainExNum;
PROCEDURE ExNumToLogical (Numb : X.ExNumType;
VAR Logical : LogicalType);
VAR
DivScale : X.ExNumType;
Scale : X.ExNumType;
Temp : X.ExNumType;
Temp2 : X.ExNumType;
LogCnt : INTEGER;
BEGIN
(* Constrain op1, op2 to be within the logical number set *)
ConstrainExNum(Numb);
(* translation scaling factor *)
X.ExNumb(65536, 0, 0, Scale);
X.ExDiv(DivScale, X.Ex1, Scale);
(* perform conversion *)
LogCnt := 0;
Logical := LogZero;
WHILE NOT X.IsZero(Numb) DO
X.ExMult(Temp2, Numb, DivScale);
X.ExTrunc(Temp2);
X.ExMult(Temp, Temp2, Scale);
X.ExSub(Temp, Numb, Temp);
IF LogCnt > LogicalSize THEN RETURN END;
(* $RangeChk- *)
Logical[LogCnt] := SYSTEM.VAL(SET, SHORT(X.ExToLongInt(Temp)));
(* $RangeChk= *)
Numb := Temp2;
INC(LogCnt);
END;
END ExNumToLogical;
PROCEDURE LogicalToExNum (Logical : LogicalType;
VAR Numb : X.ExNumType);
VAR
Scale : X.ExNumType;
Temp : X.ExNumType;
LogCnt : INTEGER;
INumb : LONGINT;
BEGIN
(* translation scaling factor *)
X.ExNumb(65536, 0, 0, Scale);
(* perform conversion *)
Numb := X.Ex0;
FOR LogCnt := LogicalSize TO 0 BY -1 DO
X.ExMult(Numb, Numb, Scale);
INumb := SYSTEM.VAL(INTEGER, Logical[LogCnt]);
IF INumb < 0 THEN INC(INumb, 10000H) END;
X.ExNumb(INumb, 0, 0, Temp);
X.ExAdd(Numb, Numb, Temp);
END;
END LogicalToExNum;
(*--------------------------------------*)
(* Local procedure to perform general *)
(* logical operations on ExNumbers. *)
PROCEDURE LOp (VAR Result : X.ExNumType;
op1 : X.ExNumType;
Oper : LogicalProc;
op2 : X.ExNumType);
VAR
i : INTEGER;
Lop1, Lop2 : LogicalType;
BEGIN
(* Translate to logicals *)
ExNumToLogical(op1, Lop1);
ExNumToLogical(op2, Lop2);
(* Operate on Lop1 and Lop2 one quad at a time *)
FOR i := 0 TO LogicalSize DO
Lop2[i] := Oper(Lop1[i], Lop2[i]);
END;
(* Translate back the result *)
LogicalToExNum(Lop2, Result);
END LOp;
(*--------------------------------------*)
(* Local procedure to perform general *)
(* single bit operations on ExNumbers. *)
PROCEDURE LBit (VAR Result : X.ExNumType;
number : X.ExNumType;
Oper : LogicalProc;
bitnum : INTEGER);
VAR
Temp : X.ExNumType;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
(* constrain bitnum from 0 to MaxBase2Bits *)
IF bitnum > MaxBase2Bits THEN
(* no bits are changed *)
Result := number;
RETURN;
END;
(* calculate 2**bitnum *)
XM.xtoi(Temp, Two, bitnum);
(* set the bitnum bit position *)
LOp(Result, number, Oper, Temp);
END LBit;
PROCEDURE ExSetBit *(VAR Result : X.ExNumType;
number : X.ExNumType;
bitnum : INTEGER);
BEGIN
LBit(Result, number, Or, bitnum);
END ExSetBit;
PROCEDURE ExClearBit *(VAR Result : X.ExNumType;
number : X.ExNumType;
bitnum : INTEGER);
BEGIN
LBit(Result, number, AndNot, bitnum);
END ExClearBit;
PROCEDURE ExToggleBit *(VAR Result : X.ExNumType;
number : X.ExNumType;
bitnum : INTEGER);
BEGIN
LBit(Result, number, Xor, bitnum);
END ExToggleBit;
PROCEDURE^ ExAnd *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
(*--------------------------------------*)
(* Local function to extract a bit from *)
(* an ExNumber. *)
PROCEDURE Bit (number : X.ExNumType;
bitnum : INTEGER) : BOOLEAN;
VAR
Temp : X.ExNumType;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
(* constrain bitnum from 0 to MaxBase2Bits - 1 *)
IF bitnum >= MaxBase2Bits THEN
(* assume FALSE *)
RETURN FALSE;
END;
(* calculate 2**bitnum *)
XM.xtoi(Temp, Two, bitnum);
(* extract the bitnum bit *)
ExAnd(number, number, Temp);
(* translate to boolean *)
RETURN NOT X.IsZero(number);
END Bit;
(*--------------------------------------*)
(* Local procedure to perform general *)
(* bit shifting operations on ExNumbers.*)
PROCEDURE LShift (VAR Result : X.ExNumType;
number : X.ExNumType;
ExOper : ExNumbProc;
bits : INTEGER);
VAR
Temp : X.ExNumType;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
(* constrain bitnum from 0 to MaxBase2Bits *)
IF bits > MaxBase2Bits THEN
(* shifted out of range *)
Result := X.Ex0;
RETURN;
END;
(* calculate 2**bits *)
XM.xtoi(Temp, Two, bits);
(* shift the number *)
ExOper(Result, number, Temp);
(* Constrain number to be within the logical number set *)
ConstrainExNum(Result);
END LShift;
(*--------------------------------------*)
(* Local procedure to perform general *)
(* bit rotation operations on ExNumbers.*)
PROCEDURE LRotate (VAR Result : X.ExNumType;
number : X.ExNumType;
Shiftright : BOOLEAN;
bits : INTEGER);
VAR
ShiftCnt : INTEGER;
SavedBit : BOOLEAN;
Half : X.ExNumType;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
(* constrain bitnum from 0 to MaxBase2Bits *)
bits := bits MOD (MaxBase2Bits + 1);
X.ExNumb(0, 5, 0, Half);
FOR ShiftCnt := 1 TO bits DO
IF Shiftright THEN
(* save the bit to be shifted *)
SavedBit := Bit(number, 0);
(* shift the number right *)
X.ExMult(number, number, Half);
X.ExTrunc(number);
IF SavedBit THEN
ExSetBit(number, number, MaxBase2Bits-1);
END;
ELSE
(* save the bit to be shifted *)
SavedBit := Bit(number, MaxBase2Bits-1);
(* shift the number left *)
X.ExMult(number, number, Two);
(* restore the saved bit *)
IF SavedBit THEN
ExSetBit(number, number, 0);
END;
END;
END;
(* Constrain number to be within the logical number set *)
Result := number;
ConstrainExNum(Result);
END LRotate;
(*--------------------------------------*)
(* Exported procedures. *)
PROCEDURE ExAnd *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
BEGIN
LOp(Result, op1, And, op2);
END ExAnd;
PROCEDURE ExOr *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
BEGIN
LOp(Result, op1, Or, op2);
END ExOr;
PROCEDURE ExXor *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
BEGIN
LOp(Result, op1, Xor, op2);
END ExXor;
PROCEDURE ExIntDiv *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
BEGIN
(* Constrain inputs to be integers *)
ConstrainExNum(op1); ConstrainExNum(op2);
X.ExDiv(Result, op1, op2);
X.ExTrunc(Result);
END ExIntDiv;
PROCEDURE ExMod *(VAR Result : X.ExNumType;
op1, op2 : X.ExNumType);
BEGIN
(* Result := op1 - (op1 DIV op2) * op2 *)
ConstrainExNum(op1); ConstrainExNum(op2);
ExIntDiv(Result, op1, op2);
X.ExMult(Result, Result, op2);
X.ExSub(Result, op1, Result);
END ExMod;
PROCEDURE ExOnesComp *(VAR Result : X.ExNumType;
number : X.ExNumType);
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
IF number.Sign = X.positive THEN
(* Subtract from the maximum number *)
X.ExSub(Result, MaxNumber, number);
ELSE
(* Subtract from the minimum number *)
X.ExSub(Result, MinNumber, number);
END;
(* Complement the sign bit *)
X.ExChgSign(Result);
END ExOnesComp;
PROCEDURE ExShl *(VAR Result : X.ExNumType;
number : X.ExNumType;
numbits : INTEGER);
BEGIN
LShift(Result, number, X.ExMult, numbits);
(* Determine the resultant sign *)
X.ExAbs(Result);
IF Bit (Result, MaxBase2Bits-1) THEN
X.ExChgSign(Result); (* negate *)
END;
END ExShl;
PROCEDURE ExRol *(VAR Result : X.ExNumType;
number : X.ExNumType;
numbits : INTEGER);
BEGIN
LRotate(Result, number, Left, numbits);
END ExRol;
PROCEDURE ExShr *(VAR Result : X.ExNumType;
number : X.ExNumType;
numbits : INTEGER);
BEGIN
LShift(Result, number, X.ExDiv, numbits);
X.ExAbs(Result); (* clear the sign *)
END ExShr;
PROCEDURE ExAshr *(VAR Result : X.ExNumType;
number : X.ExNumType;
numbits : INTEGER);
VAR
ShiftCnt : INTEGER;
SavedBit : BOOLEAN;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(number);
(* constrain bitnum from 0 to MaxBase2Bits *)
IF numbits > MaxBase2Bits THEN
(* shifted out of range *)
Result := X.Ex0;
RETURN;
END;
(* set the SavedBit to the current sign *)
SavedBit := number.Sign = X.negative;
(* shift the number *)
FOR ShiftCnt := 1 TO numbits DO
(* shift the number right *)
X.ExDiv(number, number, Two);
(* restore the saved bit *)
IF SavedBit THEN
ExSetBit(number, number, MaxBase2Bits-1);
END;
END;
(* truncate any fraction *)
Result := number;
X.ExTrunc(Result);
END ExAshr;
PROCEDURE ExRor *(VAR Result : X.ExNumType;
number : X.ExNumType;
numbits : INTEGER);
BEGIN
LRotate(Result, number, Right, numbits);
END ExRor;
(* $CopyArrays- *)
PROCEDURE StrToExInt *(S : ARRAY OF CHAR;
Base : BaseType;
VAR A : X.ExNumType);
VAR
EndCnt, InCnt : LONGINT;
Multiplier : INTEGER;
Scale, Temp : X.ExNumType;
PROCEDURE DigitIs() : LONGINT;
VAR
Str : ARRAY 2 OF CHAR;
Digits : LONGINT;
BEGIN
(* Extract a digit *)
Str[0] := S[InCnt]; Str[1] := 0X;
INC(InCnt);
IF ~Cnv.StrToInt(Str, Digits, Base) THEN
X.ExStatus := X.IllegalNumber;
RETURN 0;
END;
RETURN Digits;
END DigitIs;
BEGIN
A := X.Ex0;
InCnt := 0;
EndCnt := Str.Length(S);
X.ExNumb(Base, 0, 0, Scale);
(* skip leading blanks *)
WHILE (InCnt < EndCnt) & (S[InCnt] = ' ') DO INC(InCnt) END;
WHILE (InCnt < EndCnt) & (X.ExStatus # X.IllegalNumber) DO
X.ExNumb(DigitIs(), 0, 0, Temp);
X.ExMult(A, A, Scale);
X.ExAdd(A, A, Temp);
END;
END StrToExInt;
PROCEDURE ExIntToStr*(A : X.ExNumType;
Base : BaseType;
VAR S : ARRAY OF CHAR);
VAR
InCnt : INTEGER;
InvScale, Scale, Temp, Temp2 : X.ExNumType;
PROCEDURE PutDigits(Numb : LONGINT);
VAR
Res : ARRAY 81 OF CHAR;
Ok : BOOLEAN;
BEGIN
Ok := Cnv.IntToStr(Numb, Res, Base, 4, '0');
Str.Insert(S, 0, Res);
END PutDigits;
BEGIN
(* Constrain number to be within the logical number set *)
ConstrainExNum(A);
S := "";
InCnt := 0;
X.ExNumb(Base, 0, 0, Scale);
XM.xtoi(Scale, Scale, 4);
X.ExDiv(InvScale, X.Ex1, Scale);
(* translate number to a string *)
REPEAT
(* Temp := A MOD Scale *)
X.ExMult(Temp2, A, InvScale);
X.ExTrunc(Temp2);
X.ExMult(Temp, Temp2, Scale);
X.ExSub(Temp, A, Temp);
(* Translate to character *)
PutDigits(X.ExToLongInt(Temp));
(* Reduce A by scaling factor *)
A := Temp2;
UNTIL X.IsZero(A);
END ExIntToStr;
BEGIN
(* create the number 2 *)
X.ExNumb(2, 0, 0, Two);
(* Initialize the maximum number *)
XM.xtoi(MaxNumber, Two, MaxBase2Bits);
X.ExSub(MaxNumber, MaxNumber, X.Ex1);
(* Initialize the minimum number *)
MinNumber := MaxNumber;
X.ExChgSign(MinNumber);
(* Initialize the zero logical *)
FOR Cnt := 0 TO LogicalSize DO
LogZero[Cnt] := {};
END;
END ExIntegers.