home *** CD-ROM | disk | FTP | other *** search
- {
- You may use the following unit I have made for an encryption program
- of mine. It implements real binary arithmetic, no BCD. But be careful,
- there is currently no range checking at all, and overflows may result
- in endless loops. If you need 2048 bit integers you have to set
- BigNumLength to at least 128, a little more would be safer. Also
- notice that the routines cannot handle negative numbers.
-
- I hope you find this one useful.
-
- Jes R Klinke
- }
-
-
- PROGRAM BigNum;
-
- USES
-
- Crt, Dos;
-
- CONST
-
- BigNumLength = 20; {Number of words in value}
-
- TYPE
-
- PBigNum = ^TBigNum;
- TBigNum = object
-
- Value : ARRAY [0..BigNumLength - 1] OF WORD;
-
- PROCEDURE ASSIGN (VAR AValue : TBigNum);
- PROCEDURE AssignLong (AValue : LONGINT);
- PROCEDURE ADD (VAR AValue : TBigNum);
- PROCEDURE Subtract (VAR AValue : TBigNum);
- PROCEDURE Multiply (VAR AMultiplicator : TBigNum);
- FUNCTION Divide (VAR ADivisor : TBigNum) : BOOLEAN;
- FUNCTION Modulus (VAR ADivisor : TBigNum) : BOOLEAN;
- PROCEDURE SquareRoot;
- PROCEDURE Increment (By : WORD);
- PROCEDURE Decrement (By : WORD);
- PROCEDURE BitwiseOr (VAR AMaske : TBigNum);
- FUNCTION Compare (VAR AValue : TBigNum) : INTEGER;
- PROCEDURE Mult10;
- PROCEDURE Div10;
- PROCEDURE Mult2;
- PROCEDURE Div2;
- FUNCTION STR : STRING;
- FUNCTION Str16 : STRING;
- PROCEDURE VAL (CONST S : STRING);
- FUNCTION AsLong : LONGINT;
- END;
-
-
-
- PROCEDURE TBigNum.ASSIGN (VAR AValue : TBigNum);
- BEGIN
- MOVE (AValue.Value, Value, SIZEOF (Value) );;
- END;
-
- PROCEDURE TBigNum.AssignLong (AValue : LONGINT);
- BEGIN
- MOVE (AValue, Value [0], SIZEOF (LONGINT) );;
- FILLCHAR (Value [SIZEOF (LONGINT) SHR 1], BigNumLength SHL 1 -
- SIZEOF (LONGINT), 0);
- END;
-
- PROCEDURE TBigNum.ADD (VAR AValue : TBigNum); assembler;
- asm
-
- PUSH DS
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- LDS SI, AValue
- ADD SI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- CLD
- CLC
- @@0 : LODSW
- ADC [ES : DI], AX
- INC DI
- INC DI
- LOOP @@0
- POP DS
- END;
-
- PROCEDURE TBigNum.Subtract (VAR AValue : TBigNum); assembler;
-
- asm
-
- PUSH DS
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- LDS SI, AValue
- ADD SI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- CLD
- CLC
- @@0 : LODSW
- SBB [ES : DI], AX
- INC DI
- INC DI
- LOOP @@0
- POP DS
- END;
-
- PROCEDURE TBigNum.Multiply (VAR AMultiplicator : TBigNum); assembler;
-
- VAR
-
- Res : ARRAY [0..BigNumLength] OF WORD;
- asm
-
- PUSH DS
- PUSH BP
- STD
- LES DI, AMultiplicator
- ADD DI, OFFSET TBigNum.Value
- LDS SI, Self
- ADD SI, OFFSET TBigNum.Value
- PUSH SI
- LEA BP, Res
- XOR SI, SI
- MOV CX, BigNumLength
- XOR AX, AX
- @@8 : MOV SS : [BP + SI], AX
- ADD SI, 2
- LOOP @@8
- POP SI
- XOR BX, BX
- @@0 : MOV CX, BX
- MOV DX, CX
- SHL DX, 1
- ADD SI, DX
- INC CX
- @@1 : LODSW
- MOV DX, ES : [DI]
- ADD DI, 2
- MUL DX
- ADD SS : [BP], AX
- ADC SS : [BP + 2], DX
- JC @@3
- @@2 : LOOP @@1
- MOV DX, BX
- INC DX
- SHL DX, 1
- SUB DI, DX
- ADD SI, 2
- ADD BP, 2
- INC BX
- CMP BX, BigNumLength
- JNE @@0
- CLD
- POP BP
- LEA SI, Res
- PUSH SS
- POP DS
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- REP MOVSW
- POP DS
- JMP @@9
- @@3 : PUSH SI
- MOV DX, 1
- MOV SI, 4
- @@4 : ADD [BP + SI], DX
- INC SI
- INC SI
- JC @@4
- POP SI
- JMP @@2
- @@9 :
- END;
-
- FUNCTION TBigNum.Divide (VAR ADivisor : TBigNum) : BOOLEAN;
-
- VAR
- Bit, Res, Divisor : TBigNum;
- WholeResult : BOOLEAN;
- BEGIN
-
- Divisor.ASSIGN (ADivisor);
- WholeResult := FALSE;
- Bit.AssignLong (1);
- Res.AssignLong (0);
- WHILE Compare (Divisor) >= 0 DO
- BEGIN
- Bit.Mult2;
- Divisor.Mult2;
- END;
- WHILE (Bit.Value [0] AND 1 = 0) AND NOT WholeResult DO
- BEGIN
- Bit.Div2;
- Divisor.Div2;
- CASE Compare (Divisor) OF
- 1 :
- BEGIN
- Res.BitwiseOr (Bit);
- Subtract (Divisor);
- END;
-
- 0 :
- BEGIN
- WholeResult := TRUE;
- Res.BitwiseOr (Bit);
- Subtract (Divisor);
- END;
- END;
-
- END;
-
- ASSIGN (Res);
- Divide := WholeResult;
-
- END;
-
- FUNCTION TBigNum.Modulus (VAR ADivisor : TBigNum) : BOOLEAN;
-
- VAR
-
- Bit, Res, Divisor : TBigNum;
- WholeResult : BOOLEAN;
-
- BEGIN
-
- Divisor.ASSIGN (ADivisor);
- WholeResult := FALSE;
- Bit.AssignLong (1);
- Res.AssignLong (0);
-
- WHILE Compare (Divisor) >= 0 DO
- BEGIN
-
- Bit.Mult2;
- Divisor.Mult2;
-
- END;
-
- WHILE (Bit.Value [0] AND 1 = 0) AND NOT WholeResult DO
- BEGIN
- Bit.Div2;
- Divisor.Div2;
-
- CASE Compare (Divisor) OF
- 1 :
- BEGIN
- Res.BitwiseOr (Bit);
- Subtract (Divisor);
- END;
-
- 0 :
- BEGIN
- WholeResult := TRUE;
- Res.BitwiseOr (Bit);
- Subtract (Divisor);
- END;
-
- END;
-
- END;
-
- Modulus := WholeResult;
-
- END;
-
- PROCEDURE TBigNum.SquareRoot;
-
- VAR
-
- Guess, NewGuess : TBigNum;
-
- BEGIN
-
- NewGuess.ASSIGN (Self);
- NewGuess.Div2;
-
- REPEAT
-
- Guess.ASSIGN (NewGuess);
- NewGuess.ASSIGN (Self);
- NewGuess.Divide (Guess);
- NewGuess.ADD (Guess);
- NewGuess.Div2;
-
- UNTIL NewGuess.Compare (Guess) = 0;
-
- ASSIGN (NewGuess);
-
- END;
-
- PROCEDURE TBigNum.Increment (By : WORD); assembler;
-
- asm
-
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- CLD
- MOV AX, ES : [DI]
- ADD AX, By
- STOSW
- MOV CX, BigNumLength - 1
- @@0 : MOV AX, ES : [DI]
- ADC AX, 0
- STOSW
- LOOP @@0
- END;
-
-
- PROCEDURE TBigNum.Decrement (By : WORD); assembler;
-
- asm
-
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- CLD
- MOV AX, ES : [DI]
- SUB AX, By
- STOSW
- MOV CX, BigNumLength - 1
- @@0 : MOV AX, ES : [DI]
- SBB AX, 0
- STOSW
- LOOP @@0
- END;
-
- PROCEDURE TBigNum.BitwiseOr (VAR AMaske : TBigNum); assembler;
-
- asm
-
- PUSH DS
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- LDS SI, AMaske
- ADD SI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- CLD
- @@0 : LODSW
- OR AX, ES : [DI]
- STOSW
- LOOP @@0
- POP DS
- END;
-
- FUNCTION TBigNum.Compare (VAR AValue : TBigNum) : INTEGER; assembler;
-
- asm
- PUSH DS
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- LDS SI, AValue
- ADD SI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- MOV DX, CX
- DEC DX
- SHL DX, 1
- ADD DI, DX
- ADD SI, DX
- STD
- REPZ CMPSW
- MOV AX, 0FFFFh
- JA @@1
- MOV AX, 0000h
- JE @@1
- MOV AX, 0001h
- @@1 : POP DS
- END;
-
- PROCEDURE TBigNum.Mult10; assembler;
-
- asm
-
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- XOR BX, BX
- MOV CX, BigNumLength
- @@0 : MOV AX, [ES : DI]
- MOV DX, 10
- MUL DX
- ADD AX, BX
- ADC DX, 0
- MOV [ES : DI], AX
- INC DI
- INC DI
- MOV BX, DX
- LOOP @@0
- END;
-
- PROCEDURE TBigNum.Div10; assembler;
-
- asm
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- MOV DX, CX
- DEC DX
- SHL DX, 1
- ADD DI, DX
- XOR DX, DX
- @@0 : MOV AX, [ES : DI]
- MOV BX, 10
- DIV BX
- MOV [ES : DI], AX
- DEC DI
- DEC DI
- LOOP @@0
- END;
-
- PROCEDURE TBigNum.Mult2; assembler;
-
- asm
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- XOR BX, BX
- MOV CX, BigNumLength
- CLC
- CLD
- @@0 : MOV AX, [ES : DI]
- RCL AX, 1
- STOSW
- LOOP @@0
- END;
-
- PROCEDURE TBigNum.Div2; assembler;
-
- asm
- LES DI, Self
- ADD DI, OFFSET TBigNum.Value
- MOV CX, BigNumLength
- MOV DX, CX
- DEC DX
- SHL DX, 1
- ADD DI, DX
- XOR DX, DX
- CLC
- STD
- @@0 : MOV AX, [ES : DI]
- RCR AX, 1
- STOSW
- LOOP @@0
- END;
-
- FUNCTION TBigNum.STR : STRING;
-
- VAR
-
- M, T : TBigNum;
- Res : STRING;
- I, Ciffer : INTEGER;
-
- BEGIN
-
- M.ASSIGN (Self);
- T.AssignLong (1);
- I := 0;
- WHILE M.Compare (T) >= 0 DO
- BEGIN
- T.Mult10;
- INC (I);
- END;
- IF I <= 1 THEN
- BEGIN
- STR := CHAR (BYTE ('0') + M.Value [0]);
- END
- ELSE
- BEGIN
- Res := '';
- T.Div10;
- WHILE I > 0 DO
- BEGIN
- Ciffer := 0;
- WHILE (M.Compare (T) >= 0) DO
- BEGIN
- M.Subtract (T);
- INC (Ciffer);
- END;
- Res := Res + CHAR (BYTE ('0') + Ciffer);
- DEC (I);
- T.Div10;
- END;
- STR := Res;
- END;
- END;
-
- FUNCTION TBigNum.Str16 : STRING;
-
- CONST
- HexCif : ARRAY [0..15] OF CHAR = '0123456789ABCDEF';
- VAR
- Res : STRING;
- I : INTEGER;
- ErMed : BOOLEAN;
- BEGIN
- ErMed := FALSE;
- Res := '';
- FOR I := BigNumLength - 1 DOWNTO 0 DO
- BEGIN
- IF ErMed OR (Value [I] <> 0) THEN
- BEGIN
- IF ErMed OR (Value [I] SHR 12 AND $F <> 0) THEN
- BEGIN
- Res := Res + HexCif [Value [I] SHR 12 AND $F];
- ErMed := TRUE;
- END;
- IF ErMed OR (Value [I] SHR 8 AND $F <> 0) THEN
- BEGIN
- Res := Res + HexCif [Value [I] SHR 8 AND $F];
- ErMed := TRUE;
- END;
- IF ErMed OR (Value [I] SHR 4 AND $F <> 0) THEN
- BEGIN
- Res := Res + HexCif [Value [I] SHR 4 AND $F];
- ErMed := TRUE;
- END;
- Res := Res + HexCif [Value [I] AND $F];
- ErMed := TRUE;
- END;
- END;
- Str16 := Res;
- END;
-
- PROCEDURE TBigNum.VAL (CONST S : STRING);
- VAR
- I : INTEGER;
- BEGIN
- AssignLong (0);
- I := 1;
- WHILE I <= LENGTH (S) DO
- BEGIN
- Mult10;
- Increment (BYTE (S [I]) - BYTE ('0') );
- INC (I);
- END;
- END;
-
- FUNCTION TBigNum.AsLong : LONGINT;
- VAR
- Res : ^LONGINT;
-
- BEGIN
- Res := @Value [0];
- AsLong := Res^;
- END;
-
- VAR
- ABigNum : TBigNum;
- I : INTEGER;
-
-
- BEGIN
- ABigNum.AssignLong (1);
- FOR I := 1 TO 260 DO
- BEGIN
- WRITELN (ABigNum.STR : 79);
- ABigNum.Mult2;
- END;
- FOR I := 1 TO 260 DO
- BEGIN
- WRITELN (ABigNum.STR : 79);
- ABigNum.Div2;
- END;
- WRITELN (ABigNum.STR : 79);
- WRITE ('Press enter to exit.');
- READLN;
- END.
-
-