size : 21596
uploaded_on : Mon May 17 00:00:00 1999
modified_on : Wed Dec 8 14:03:40 1999
title : BigNum
org_filename : Bignum.pas
author : Jes R. Klinke
authoremail : jesk@diku.dk
description : Class for handling arbitrarily large integers.
keywords :
tested : D4
submitted_by : The CKB Crew
submitted_by_email : ckb@netalive.org
uploaded_by : nobody
modified_by : nobody
owner : nobody
lang : pas
file-type : text/plain
category : pascal-alg-maths
__END_OF_HEADER__
unit BigNum;
{ BigNum v2.1a, 32-bit for Delphi by Jes R. Klinke
Implements calculations on integers of arbitrary size.
All operations necessary for cryptographic applications are provided,
for functions generating large prime numbers look in BigPrime.pas.
You may use this unit for whatever you want. But if you make a commercial
product at least send me a copy of it, please.
New in version 2.1:
* Optimizations
The assembler routines have been further optimized, and the reallocation
algorithm changed to prevent many reallocations with slowly increasing
sizes.
New in version 2:
* Dynamic size
Each instance of TBigNum has just enough memory allocated to it to
keep its current value. You don't have to specify a fixed BigNumSize.
* Negative numbers
Most of the calculations now support negative values.
* More efficient calculations
As each instance of TBigNum keeps track of how many words are actually
used in it's value, only the necessary calculations are performed.
This particularly speeds up the multiplication, as lots of
MUL's with zero words are avoided.
New in Delphi 32-bit release:
* Special Object Pascal features
Properties provide easier syntax.
Exceptions add understandable error messages.
To do's:
* Pentium optimization
I have done some minor optimizations, i.e. swapping of instructions to
prevent data-depedency between adjacent instructions, replacement of
x86 string instructions with two or more simpler instructions. But the
code is still far from optimal, unfortunately I do not know much about
optimizing assembler, so if anyone has some suggestions please feel free
to mail me.
Any comment or bug reports are welcome.
You can reach me at jesk@diku.dk or jesk@dk-online.dk.
My snail-mail address is Jes Rahbek Klinke
Haandvaerkerhaven 3, 2. mf
2400 Copenhagen NV
}
interface
uses
SysUtils, BigTestU;
type
PIntArr = ^TIntArr;
TIntArr = array [0..999] of LongInt;
TBigNum = class
private
Value: PIntArr;
Alloc, Used: Integer;
Sign: Boolean;
{ obsolete functions, use the properties AsLong and AsString }
function ToLong: LongInt;
procedure FromLong(AValue: LongInt);
function ToStr: string;
procedure FromStr(S: string);
{ internal procedures for memory management }
procedure Realloc(Ints: Integer; Preserve: Boolean);
function Critical: Boolean;
procedure CountUsed;
public
constructor Create;
destructor Destroy; override;
procedure Assign(AValue: TBigNum);
procedure Add(AValue: TBigNum);
procedure Subtract(AValue: TBigNum);
procedure Multiply(AValue: TBigNum);
function Divide(ADivisor: TBigNum): Boolean;
function Modulo(ADivisor: TBigNum): Boolean;
procedure PowerModulo(AExponent, AModulo: TBigNum);
procedure BitwiseOr(AMask: TBigNum);
function Compare(AValue: TBigNum): Integer;
procedure Mult10;
function Div10: Integer;
procedure Mult2;
procedure Div2;
function Negative: Boolean;
procedure Swap(AValue: TBigNum);
property AsLong: LongInt read ToLong write FromLong;
property AsString: string read ToStr write FromStr;
{ procedures working on absolute values only, primarily for internal use. }
procedure AbsIncrement(By: LongInt);
procedure AbsDecrement(By: LongInt);
function AbsCompare(AValue: TBigNum): Integer;
procedure AbsAdd(AValue: TBigNum);
procedure AbsSubtract(AValue: TBigNum);
function AbsDivide(ADivisor: TBigNum): Boolean;
function AbsModulo(ADivisor: TBigNum): Boolean;
function AbsModuloLong(ADivisor: Integer): Integer;
end;
EBigNum = class(Exception);
EBigNumInvalidArg = class(EBigNum);
EBigNumDivByZero = class(EBigNum);
EBigNumTooBig = class(EBigNum);
implementation
constructor TBigNum.Create;
begin
inherited Create;
Alloc := 0;
Used := 0;
end;
destructor TBigNum.Destroy;
begin
FreeMem(Value, Alloc * SizeOf(Integer));
inherited Destroy;
end;
procedure TBigNum.Assign(AValue: TBigNum);
begin
if Alloc < AValue.Used then
Realloc(AValue.Used, False);
Used := AValue.Used;
Move(AValue.Value^, Value^, Used shl 2);
FillChar(Value^[Used], (Alloc - Used) shl 2, 0);
Sign := AValue.Sign;
end;
procedure TBigNum.Add(AValue: TBigNum);
var
MValue: TBigNum;
begin
if Sign xor AValue.Sign then
if AbsCompare(AValue) >= 0 then
AbsSubtract(AValue)
else
begin
MValue := TBigNum.Create;
MValue.Assign(AValue);
Self.Swap(MValue);
AbsSubtract(MValue);
MValue.Destroy;
end
else
AbsAdd(AValue);
end;
procedure TBigNum.Subtract(AValue: TBigNum);
var
MValue: TBigNum;
begin
if Sign xor AValue.Sign then
AbsAdd(AValue)
else
if AbsCompare(AValue) >= 0 then
AbsSubtract(AValue)
else
begin
MValue := TBigNum.Create;
MValue.Assign(AValue);
Self.Swap(MValue);
AbsSubtract(MValue);
MValue.Destroy;
Sign := not Sign;
end;
end;
procedure TBigNum.Multiply(AValue: TBigNum);
var
Needed: Integer;
Result: PIntArr;
SmallVal, BigVal: PIntArr;
SmallSize, BigSize: Integer;
begin
if Used = 0 then
Exit;
if AValue.Used = 0 then
begin
Used := 0;
Exit;
end;
Sign := Sign xor AValue.Sign;
Needed := Used + AValue.Used + 1;
GetMem(Result, Needed * SizeOf(Integer));
FillChar(Result^, Needed * SizeOf(Integer), 0);
if Used > AValue.Used then
begin
SmallVal := AValue.Value;
SmallSize := AValue.Used;
BigVal := Value;
BigSize := Used;
end
else
begin
BigVal := AValue.Value;
BigSize := AValue.Used;
SmallVal := Value;
SmallSize := Used;
end;
asm
PUSH EDI
PUSH ESI
PUSH EBX
XOR EDX,EDX
@@0:PUSH EDX
MOV EDI,SmallVal
LEA EDI,[EDI+4*EDX]
MOV EAX,[EDI]
MOV EDI,Result
LEA EDI,[EDI+4*EDX]
MOV ESI,BigVal
MOV ECX,BigSize
PUSH EBP
MOV EBP,EAX
XOR EDX,EDX
@@1:MOV EAX,[ESI]
MOV EBX,EDX
MUL EBP
ADD EBX,EAX
MOV EAX,[EDI]
ADC EDX,0
ADD EAX,EBX
MOV [EDI],EAX
ADC EDX,0
ADD ESI,4
ADD EDI,4
DEC ECX
JNE @@1
MOV EAX,[EDI]
ADD EAX,EDX
MOV [EDI],EAX
POP EBP
POP EDX
INC EDX
CMP EDX,SmallSize
JNE @@0
POP EBX
POP ESI
POP EDI
end;
Realloc(Needed, False);
Move(Result^, Value^, Needed * SizeOf(Integer));
if Alloc - Needed > 0 then
FillChar(Value^[Needed], (Alloc - Needed) * SizeOf(Integer), 0);
FreeMem(Result, Needed * SizeOf(Integer));
CountUsed;
end;
{ Note: At first sight, you might think, that Divide and Modulo gives wrong
results for negative values. This depends on the definition of the quoient
and remainder.
The definition used by these routines is:
Given the divident N and divisor D, the quotient Q and remainder R is then
given by the equation
N = D * Q + R,
where the absolute value of R is less than the absolute value of D, and R
has the same sign as D.
This will prove to be very convinient.}
function TBigNum.Divide(ADivisor: TBigNum): Boolean;
begin
if Sign xor ADivisor.Sign then
begin
Subtract(ADivisor);
AbsDecrement(1);
Result := AbsDivide(ADivisor);
Sign := not Sign;
end
else
begin
Result := AbsDivide(ADivisor);
end;
end;
function TBigNum.Modulo(ADivisor: TBigNum): Boolean;
begin
if Sign xor ADivisor.Sign then
begin
Subtract(ADivisor);
AbsDecrement(1);
Result := AbsModulo(ADivisor);
Add(ADivisor);
AbsDecrement(1);
end
else
begin
Result := AbsModulo(ADivisor);
end;
end;
procedure TBigNum.PowerModulo(AExponent, AModulo: TBigNum);
var
Result, A: TBigNum;
I: Integer;
begin
if AExponent.Sign then
raise EBigNumInvalidArg.Create('Negative exponent in PowerModulo');
Result := TBigNum.Create;
A := TBigNum.Create;
Result.AsLong := 1;
A.Assign(Self);
for I := 0 to AExponent.Used * SizeOf(Integer) * 8 - 1 do
begin
if AExponent.Value^[I shr 5] and (1 shl (I and 31)) <> 0 then
begin
Result.Multiply(A);
Result.Modulo(AModulo);
end;
A.Multiply(A);
A.Modulo(AModulo);
end;
Assign(Result);
A.Destroy;
Result.Destroy;
end;
procedure TBigNum.BitwiseOr(AMask: TBigNum);
begin
if AMask.Used > Used then
Realloc(AMask.Used, True);
asm
PUSH EDI
PUSH ESI
MOV EDI,Self
MOV EDI,[EDI.TBigNum.Value]
MOV ESI,AMask
MOV ECX,[ESI.TBigNum.Used]
OR ECX,ECX
JE @@1
MOV ESI,[ESI.TBigNum.Value]
@@0:MOV EAX,[ESI]
OR EAX,[EDI]
ADD ESI,4
MOV [EDI],EAX
ADD EDI,4
DEC ECX
JNE @@0
@@1:POP ESI
POP EDI
end;
CountUsed;
end;
function TBigNum.Compare(AValue: TBigNum): Integer;
begin
if Sign xor AValue.Sign then
if Sign then
Compare := -1
else
Compare := 1
else
if Sign then
Compare := -AbsCompare(AValue)
else
Compare := AbsCompare(AValue);
end;
procedure TBigNum.Mult10;
begin
Realloc(Used + 1, True);
asm
PUSH EDI
PUSH ESI
PUSH EBX
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
OR ECX,ECX
JE @@1
MOV EDI,[EDI.TBigNum.Value]
MOV ESI,10
XOR EBX,EBX
@@0:MOV EAX,[EDI]
MUL ESI
ADD EAX,EBX
MOV [EDI],EAX
ADC EDX,0
ADD EDI,4
MOV EBX,EDX
DEC ECX
JNE @@0
MOV [EDI],EBX
@@1:POP EBX
POP ESI
POP EDI
end;
CountUsed;
end;
function TBigNum.Div10: Integer;
begin
asm
PUSH EDI
PUSH EBX
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
XOR EDX,EDX
OR ECX,ECX
JE @@1
MOV EDI,[EDI.TBigNum.Value]
MOV EDX,ECX
LEA EDI,[EDI+4*EDX]
XOR EDX,EDX
MOV EBX,10
@@0:SUB EDI,4
MOV EAX,[EDI]
DIV EBX
MOV [EDI],EAX
DEC ECX
JNE @@0
@@1:MOV @Result,EDX
POP EBX
POP EDI
end;
CountUsed;
end;
procedure TBigNum.Mult2;
begin
if Critical then
begin
Realloc(Used + 1, True);
Used := Used + 1;
end;
asm
PUSH EDI
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
OR ECX,ECX
JE @@1
MOV EDI,[EDI.TBigNum.Value]
CLC
@@0:MOV EAX,[EDI]
ADC EAX,EAX
MOV [EDI],EAX
ADC EAX,EAX
ADD EDI,4
SHR EAX,1
DEC ECX
JNE @@0
@@1:POP EDI
end;
CountUsed;
end;
procedure TBigNum.Div2;
begin
asm
PUSH EDI
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
OR ECX,ECX
JE @@1
MOV EDI,[EDI.TBigNum.Value]
MOV EDX,[EDI+4*ECX-4]
SHR EDX,1
MOV [EDI+4*ECX-4],EDX
DEC ECX
JZ @@1
MOV EAX,[EDI+4*ECX-4]
DEC ECX
JZ @@3
@@0:RCR EAX,1
MOV [EDI+4*ECX],EAX
MOV EAX,[EDI+4*ECX-4]
DEC ECX
JNZ @@0
@@3:RCR EAX,1
MOV [EDI],EAX
@@1:OR EDX,EDX
JNZ @@2
MOV EDI,Self
DEC DWORD PTR [EDI.TBigNum.Used]
@@2:POP EDI
end;
end;
function TBigNum.Negative: Boolean;
begin
Result := Sign;
end;
procedure TBigNum.Swap(AValue: TBigNum);
var
MI: Integer;
MP: PIntArr;
MB: Boolean;
begin
MI := Alloc;
Alloc := AValue.Alloc;
AValue.Alloc := MI;
MI := Used;
Used := AValue.Used;
AValue.Used := MI;
MP := Value;
Value := AValue.Value;
AValue.Value := MP;
MB := Sign;
Sign := AValue.Sign;
AValue.Sign := MB;
end;
function TBigNum.AbsCompare(AValue: TBigNum): Integer;
begin
if Used > AValue.Used then
AbsCompare := 1
else if Used < AValue.Used then
AbsCompare := -1
else if Used = 0 then
AbsCompare := 0
else
asm
PUSH EDI
PUSH ESI
MOV EDI,Self
MOV EDI,[EDI.TBigNum.Value]
MOV ESI,AValue
MOV ECX,[ESI.TBigNum.Used]
MOV ESI,[ESI.TBigNum.Value]
MOV EDX,ECX
DEC EDX
SHL EDX,2
ADD EDI,EDX
ADD ESI,EDX
STD
REPZ CMPSD
{ MOV EAX,[ESI]
MOV EDX,[EDI]
SUB ESI,4
SUB EDI,4}
MOV @Result,0FFFFFFFFh
JA @@1
MOV @Result,000000000h
JE @@1
MOV @Result,000000001h
@@1: CLD
POP ESI
POP EDI
end;
end;
procedure TBigNum.AbsIncrement(By: LongInt);
begin
if (Used = 0) or Critical then
begin
Inc(Used);
Realloc(Used, True);
end;
asm
PUSH EDI
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
DEC ECX
MOV EDI,[EDI.TBigNum.Value]
ADD EDI,4
MOV EAX,[EDI-4]
ADD EAX,By
MOV [EDI-4],EAX
JNC @@1
ADD EDX,EDX
OR ECX,ECX
JZ @@1
SHR EDX,1
@@0:MOV EAX,[EDI]
ADC EAX,0
MOV [EDI],EAX
ADC EAX,EAX
ADD EDI,4
SHR EAX,1
JC @@0
@@1:POP EDI
end;
CountUsed;
end;
procedure TBigNum.AbsDecrement(By: LongInt);
begin
asm
PUSH EDI
MOV EDI,Self
MOV ECX,[EDI.TBigNum.Used]
DEC ECX
MOV EDI,[EDI.TBigNum.Value]
CLD
ADD EDI,4
MOV EAX,[EDI-4]
SUB EAX,By
MOV [EDI-4],EAX
ADD EDX,EDX
OR ECX,ECX
JZ @@1
SHR EDX,1
@@0:MOV EAX,[EDI]
SBB EAX,0
MOV [EDI],EAX
ADC EAX,EAX
ADD EDI,4
SHR EAX,1
DEC ECX
JNE @@0
@@1:POP EDI
end;
CountUsed;
end;
procedure TBigNum.AbsAdd(AValue: TBigNum);
var
RealAdds, ExtraAdds: Integer;
begin
if AValue.Used >= Alloc then
if AValue.Critical or (AValue.Used = Alloc) and (Alloc = Used) and Critical then
Realloc(AValue.Used + 1, True)
else
if AValue.Used > Alloc then
Realloc(AValue.Used, True)
else if AValue.Used < Alloc then
if (Used = Alloc) and Critical then
Realloc(Used + 1, True);
RealAdds := AValue.Used;
ExtraAdds := Alloc - RealAdds;
asm
PUSH EDI
PUSH ESI
MOV EDI,Self
MOV EDI,[EDI.TBigNum.Value]
MOV ESI,AValue
MOV ESI,[ESI.TBigNum.Value]
MOV ECX,RealAdds
OR ECX,ECX
JZ @@2
LEA EDI,[EDI+4*ECX]
LEA ESI,[ESI+4*ECX]
NEG ECX
MOV EAX,[ESI+4*ECX]
CLC
@@0:ADC [EDI+4*ECX],EAX
MOV EAX,[ESI+4+4*ECX]
INC ECX
JNZ @@0
MOV ECX,ExtraAdds
JECXZ @@2
LEA EDI,[EDI+4*ECX]
NEG ECX
@@1:ADC DWORD PTR [EDI+4*ECX],0
INC ECX
JNZ @@1
@@2:POP ESI
POP EDI
end;
CountUsed;
end;
procedure TBigNum.AbsSubtract(AValue: TBigNum);
begin
asm
PUSH EDI
PUSH ESI
MOV EDI,Self
MOV EDX,[EDI.TBigNum.Used]
MOV EDI,[EDI.TBigNum.Value]
MOV ESI,AValue
MOV ECX,[ESI.TBigNum.Used]
MOV ESI,[ESI.TBigNum.Value]
SUB EDX,ECX
OR ECX,ECX
JZ @@2
LEA EDI,[EDI+4*ECX]
LEA ESI,[ESI+4*ECX]
NEG ECX
MOV EAX,[ESI+4*ECX]
CLC
@@0:SBB [EDI+4*ECX],EAX
MOV EAX,[ESI+4+4*ECX]
INC ECX
JNZ @@0
ADC ECX,ECX
OR EDX,EDX
JZ @@2
SHR ECX,1
LEA EDI,[EDI+4*EDX]
NEG EDX
@@1:SBB DWORD PTR [EDI+4*EDX],0
INC EDX
JNZ @@1
@@2:POP ESI
POP EDI
end;
CountUsed;
end;
function TBigNum.AbsDivide(ADivisor: TBigNum): Boolean;
var
Bit, Res, Divisor: TBigNum;
NoRemainder: Boolean;
begin
if ADivisor.Used = 0 then
raise EBigNumDivByZero.Create('AbsDivide by zero');
Bit := TBigNum.Create;
Res := TBigNum.Create;
Divisor := TBigNum.Create;
Divisor.Assign(ADivisor);
NoRemainder := False;
Bit.AsLong := 1;
Res.AsLong := 0;
while AbsCompare(Divisor) >= 0 do
begin
Bit.Mult2;
Divisor.Mult2;
end;
while (Bit.Value^[0] and 1 = 0) and not NoRemainder do
begin
Bit.Div2;
Divisor.Div2;
case AbsCompare(Divisor) of
1:
begin
Res.BitwiseOr(Bit);
AbsSubtract(Divisor);
end;
0:
begin
NoRemainder := True;
Res.BitwiseOr(Bit);
AbsSubtract(Divisor);
end;
end;
end;
AbsDivide := NoRemainder;
Assign(Res);
Divisor.Destroy;
Res.Destroy;
Bit.Destroy;
end;
function TBigNum.AbsModulo(ADivisor: TBigNum): Boolean;
var
Divisor: TBigNum;
NoRemainder: Boolean;
Dif, Count: Integer;
function MulSub(Src, Sub, Res: PIntArr; Mul, Size: Integer): Integer;
asm
MOV ECX,Size
MOV ESI,Src
MOV EDI,Res
@@0:MOV EAX,[ESI]
ADD ESI,4
MOV [EDI],EAX
ADD EDI,4
DEC ECX
JNZ @@0
MOV EDI,Res
MOV ESI,Sub
MOV ECX,Size
PUSH EBP
MOV EBP,Mul
MOV EBX,0
CLC
PUSHF
@@1:
MOV EAX,[ESI]
ADD ESI,4
MUL EBP
ADD EAX,EBX
ADC EDX,0
JNC @@2
INT 3
@@2:
MOV EBX,EDX
POPF
SBB [EDI],EAX
PUSHF
ADD EDI,4
DEC ECX
JNZ @@1
POPF
SBB EAX,EAX
end;
begin
if ADivisor.Used = 0 then
raise EBigNumDivByZero.Create('AbsModulo by zero');
Divisor := TBigNum.Create;
Divisor.Assign(ADivisor);
NoRemainder := False;
Divisor.ReAlloc(Used, True);
Dif := Used - Divisor.Used;
Count := 0;
if Dif > 0 then
begin
Move(Divisor.Value^[0], Divisor.Value^[Dif], Divisor.Used shl 2);
FillChar(Divisor.Value^[0], Dif shl 2, 0);
Inc(Divisor.Used, Dif);
Count := Dif * 32;
end;
while AbsCompare(Divisor) >= 0 do
begin
Inc(Count);
Divisor.Mult2;
end;
while (Count <> 0) and not NoRemainder do
begin
Divisor.Div2;
case AbsCompare(Divisor) of
1:
begin
AbsSubtract(Divisor);
end;
0:
begin
NoRemainder := True;
AbsSubtract(Divisor);
end;
end;
Dec(Count);
end;
AbsModulo := NoRemainder;
Divisor.Destroy;
end;
function TBigNum.AbsModuloLong(ADivisor: Integer): Integer;
asm
PUSH ESI
PUSH EBX
MOV EBX,ADivisor
MOV ESI,Self
MOV ECX,[ESI.TBigNum.Used]
MOV ESI,[ESI.TBigNum.Value]
MOV EDX,ECX
DEC EDX
SHL EDX,2
ADD ESI,EDX
XOR EDX,EDX
STD
@@0:MOV EAX,[ESI]
SUB ESI,4
DIV EBX
DEC ECX
JNZ @@0
MOV EAX,EDX
CLD
POP EBX
POP ESI
end;
procedure TBigNum.FromLong(AValue: LongInt);
begin
if AValue < 0 then
begin
Sign := True;
AValue := -AValue;
end
else
Sign := False;
if Alloc < 1 then
Realloc(1, False);
Move(AValue, Value^[0], SizeOf(LongInt));;
Used := 1;
if Alloc > Used then
FillChar(Value^[Used], (Alloc - Used) shl 2, 0);
CountUsed;
end;
function TBigNum.ToLong: LongInt;
begin
if (Used > 1) or (Used = 1) and Critical then
raise EBigNumTooBig.Create('Value don''t fit in a LongInt');
if Used = 1 then
Result := Value^[0]
else
Result := 0;
if Sign then
Result := -Result;
end;
procedure TBigNum.FromStr(S: string);
var
I: Integer;
begin
if Length(S) = 0 then
raise EBigNumInvalidArg.Create('Not a valid number in FromStr');
Used := 0;
if S[1] = '-' then
begin
Sign := True;
I := 2;
end
else
begin
Sign := False;
I := 1;
end;
while I <= Length(S) do
begin
Mult10;
if (S[I] > '9') or (S[I] < '0') then
raise EBigNumInvalidArg.Create('Not a valid number in FromStr');
AbsIncrement(Byte(S[I]) - Byte('0'));
Inc(I);
end;
end;
function TBigNum.ToStr: string;
var
M: TBigNum;
Res: string;
begin
if Used = 0 then
begin
Result := '0';
Exit;
end;
M := TBigNum.Create;
M.Assign(Self);
while M.Used > 0 do
Res := Char(Byte('0') + M.Div10) + Res;
if Sign then
Result := '-' + Res
else
Result := Res;
M.Destroy;
end;
procedure TBigNum.Realloc(Ints: Integer; Preserve: Boolean);
var
NewValue: PIntArr;
begin
if Ints <= Alloc then
begin
if Preserve then
begin
FillChar(Value^[Used], (Alloc - Used) shl 2, 0);
end;
Exit;
end;
if Ints < Alloc * 2 then
Ints := Alloc * 2;
if Preserve then
begin
GetMem(NewValue, Ints * SizeOf(Integer));
Move(Value^, NewValue^, Used shl 2);
FillChar(NewValue^[Used], (Ints - Used) shl 2, 0);
FreeMem(Value, Alloc * SizeOf(Integer));
Value := NewValue;
Alloc := Ints;
end
else
begin
FreeMem(Value, Alloc * SizeOf(Integer));
Alloc := Ints;
GetMem(Value, Alloc * SizeOf(Integer));
end;
end;
function TBigNum.Critical: Boolean;
begin
Critical := (Used > 0) and (Value^[Used - 1] and (1 shl (SizeOf(Integer) * 8 - 1)) <> 0);
end;
procedure TBigNum.CountUsed;
begin
Used := Alloc;
while (Used > 0) and (Value^[Used - 1] = 0) do
Dec(Used);
end;
(*
var
BigA, BigB: TBigNum;
I: Integer;
begin
BigA.Init; { Caution: Because of the new dynamic memory allocation }
BigB.Init; { you have to use Init and Done. }
WriteLn('Fibonacci numbers:');
BigA.Val('0');
BigB.Val('1');
for I := 1 to 370 do
begin
WriteLn(BigB.Str: 79);
BigA.Add(BigB);
BigA.Swap(BigB);
end;
WriteLn(BigB.Str: 79);
WriteLn('Factorials:');
BigA.Val('1');
BigB.Val('1');
for I := 1 to 49 do
begin
WriteLn(BigA.Str: 70, ' = ', BigB.Str, '!');
BigB.AbsIncrement(1);
BigA.Multiply(BigB);
end;
for I := 1 to 49 do
begin
WriteLn(BigA.Str: 70, ' = ', BigB.Str, '!');
BigA.Divide(BigB);
BigB.AbsDecrement(1);
end;
WriteLn(BigA.Str: 70, ' = ', BigB.Str, '!');
WriteLn('Powers of 2:');
BigA.Val('1');
BigB.Val('2');
for I := 1 to 250 do
begin
WriteLn(BigA.Str: 79);
BigA.Multiply(BigB);
end;
for I := 1 to 250 do
begin
WriteLn(BigA.Str: 79);
BigA.Divide(BigB);
end;
WriteLn(BigA.Str: 79);
BigB.Done;
BigA.Done;
Write('Press enter to exit.');
ReadLn;*)
end.