xtool/contrib/fundamentals/Utils/flcHugeInt.pas

7641 lines
208 KiB
ObjectPascal
Raw Blame History

{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcHugeInt.pas }
{ File version: 5.33 }
{ Description: HugeInt functions }
{ }
{ Copyright: Copyright (c) 2001-2020, David J Butler }
{ All rights reserved. }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2001/11/18 0.01 HugeWord. }
{ 2001/11/19 0.02 HugeMultiplyFFT. }
{ 2003/10/01 0.03 HugeInt. }
{ 2007/08/08 4.04 Revised for Fundamentals 4. }
{ 2007/08/16 4.05 Revised HugeWord. }
{ 2007/08/22 4.06 PowerAndMod. }
{ 2008/01/20 4.07 HugeWord primality testing. }
{ 2010/01/07 4.08 Minor revision. }
{ 2010/08/05 4.09 Changed HugeWord structure to separately keep track of }
{ allocated and used size. }
{ 2010/08/06 4.10 Revision, improved tests and bug fixes. }
{ 2010/08/08 4.11 Improved ISqrt algorithm, HugeInt tests. }
{ 2010/08/09 4.12 Optimisation and bug fix. }
{ 2010/12/01 4.13 HugeWordAssignBuf. }
{ 2011/01/24 4.14 Revised for FreePascal 2.4.2. }
{ 2011/01/25 4.15 THugeInt class. }
{ 2011/04/02 4.16 Compilable with Delphi 5. }
{ 2011/09/03 4.17 Fix for Delphi 7 in HugeIntToInt32. }
{ 2011/10/18 4.18 Minor optimisation. }
{ 2012/11/15 4.19 Improvements to HugeWordIsPrime_MillerRabin courtesy of }
{ Wolfgang Ehrhardt. }
{ 2015/03/29 4.20 Minor optimisations. }
{ 2015/04/01 4.21 Compilable with FreePascal 2.6.2. }
{ 2015/04/20 4.22 Float-type conversion functions. }
{ 2015/06/10 4.23 Fix in HugeWordIsPrime_MillerRabin. }
{ 2016/01/09 5.24 Revised for Fundamentals 5. }
{ 2018/07/17 5.25 Word32 changes. }
{ 2018/08/12 5.26 String type changes. }
{ 2019/09/02 5.27 Initial static buffer for HugeWord. }
{ 2019/09/02 5.28 Optimisation to HugeWordSubtract and HugeWordMod. }
{ 2019/09/02 5.29 Unroll loops in HugeWordShl1 and HugeWordCompare. }
{ 2019/10/07 5.30 Optimisation to HugeWordDivide and HugeWordMod. }
{ 2020/03/08 5.31 HugeIntMod_T, HugeIntMod_F, HugeIntMod_E. }
{ 2020/03/10 5.32 Minor optimisations. }
{ 2020/03/20 5.33 Define exception classes. }
{ }
{ Supported compilers: }
{ }
{ Delphi 2010-10.4 Win32/Win64 5.33 2020/06/02 }
{ Delphi 10.2-10.4 Linux64 5.33 2020/06/02 }
{ FreePascal 3.0.4 Win64 5.33 2020/06/02 }
{ }
{******************************************************************************}
{$INCLUDE ..\flcInclude.inc}
{$IFDEF FREEPASCAL}
{$Q-}
{$ENDIF}
{$IFDEF DEBUG}
{$IFDEF TEST}
{$DEFINE HUGEINT_TEST}
{$ENDIF}
{$ENDIF}
{$IFDEF DEBUG}
{$IFDEF PROFILE}
{$IFDEF OS_MSWIN}
{$DEFINE HUGEINT_PROFILE}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$Q-,R-}
unit flcHugeInt;
interface
uses
{ System }
SysUtils,
{ Fundamentals }
flcStdTypes;
{ }
{ Exceptions }
{ }
type
EHugeIntDivByZero = class(Exception);
EHugeIntRangeError = class(Exception);
EHugeIntConvertError = class(EConvertError);
EHugeIntInvalidOp = class(Exception);
{ }
{ Structures }
{ }
type
HugeWordElement = Word32;
PHugeWordElement = ^HugeWordElement;
const
HugeWordElementSize = SizeOf(HugeWordElement); // 4 bytes
HugeWordElementBits = HugeWordElementSize * 8; // 32 bits
const
HugeWordStaticBufferSize = 132; // 528 bytes, 4224 bits
type
HugeWord = record
Used : Integer;
Alloc : Integer;
Data : Pointer;
InitBuf : array[0..HugeWordStaticBufferSize - 1] of HugeWordElement;
end;
PHugeWord = ^HugeWord;
type
THugeWordCallbackProc = function (const Data: NativeInt): Boolean;
type
HugeInt = record
Sign : Int8; // -1, 0 or 1
Value : HugeWord;
end;
PHugeInt = ^HugeInt;
{ }
{ HugeWord }
{ }
procedure HugeWordInit(out A: HugeWord);
procedure HugeWordFinalise(var A: HugeWord);
procedure HugeWordClearAndFinalise(var A: HugeWord);
function HugeWordGetSize(const A: HugeWord): Integer; {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordGetSizeInBits(const A: HugeWord): Integer; {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordSetSize_NoZeroMem(var A: HugeWord; const Size: Integer);
procedure HugeWordSetSize(var A: HugeWord; const Size: Integer);
procedure HugeWordSetSizeInBits(var A: HugeWord; const Size: Integer);
function HugeWordGetElement(const A: HugeWord; const I: Integer): Word32; {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordSetElement(const A: HugeWord; const I: Integer; const B: Word32); {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordGetFirstElementPtr(const A: HugeWord): PHugeWordElement; {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordGetLastElementPtr(const A: HugeWord): PHugeWordElement; {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordNormalise(var A: HugeWord);
procedure HugeWordInitZero(out A: HugeWord); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordInitOne(out A: HugeWord);
procedure HugeWordInitWord32(out A: HugeWord; const B: Word32);
procedure HugeWordInitInt32(out A: HugeWord; const B: Int32);
procedure HugeWordInitInt64(out A: HugeWord; const B: Int64);
procedure HugeWordInitDouble(out A: HugeWord; const B: Double);
procedure HugeWordInitHugeWord(out A: HugeWord; const B: HugeWord);
procedure HugeWordAssignZero(var A: HugeWord); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordAssignOne(var A: HugeWord); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordAssignWord32(var A: HugeWord; const B: Word32);
procedure HugeWordAssignInt32(var A: HugeWord; const B: Int32);
procedure HugeWordAssignInt64(var A: HugeWord; const B: Int64);
procedure HugeWordAssignDouble(var A: HugeWord; const B: Double);
procedure HugeWordAssign(var A: HugeWord; const B: HugeWord);
procedure HugeWordAssignHugeIntAbs(var A: HugeWord; const B: HugeInt);
procedure HugeWordAssignBuf(var A: HugeWord; const Buf; const BufSize: Integer;
const ReverseByteOrder: Boolean);
procedure HugeWordAssignBufStrB(var A: HugeWord; const Buf: RawByteString;
const ReverseByteOrder: Boolean);
procedure HugeWordSwap(var A, B: HugeWord);
function HugeWordIsZero(const A: HugeWord): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordIsOne(const A: HugeWord): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordIsTwo(const A: HugeWord): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeWordIsOdd(const A: HugeWord): Boolean;
function HugeWordIsEven(const A: HugeWord): Boolean;
function HugeWordIsWord32Range(const A: HugeWord): Boolean;
function HugeWordIsWord64Range(const A: HugeWord): Boolean;
function HugeWordIsWord128Range(const A: HugeWord): Boolean;
function HugeWordIsWord256Range(const A: HugeWord): Boolean;
function HugeWordIsInt32Range(const A: HugeWord): Boolean;
function HugeWordIsInt64Range(const A: HugeWord): Boolean;
function HugeWordIsInt128Range(const A: HugeWord): Boolean;
function HugeWordIsInt256Range(const A: HugeWord): Boolean;
function HugeWordToWord32(const A: HugeWord): Word32;
function HugeWordToInt32(const A: HugeWord): Int32;
function HugeWordToInt64(const A: HugeWord): Int64;
function HugeWordToDouble(const A: HugeWord): Double;
function HugeWordEqualsWord32(const A: HugeWord; const B: Word32): Boolean;
function HugeWordEqualsInt32(const A: HugeWord; const B: Int32): Boolean;
function HugeWordEqualsInt64(const A: HugeWord; const B: Int64): Boolean;
function HugeWordEquals(const A, B: HugeWord): Boolean;
function HugeWordCompareWord32(const A: HugeWord; const B: Word32): Integer;
function HugeWordCompareInt32(const A: HugeWord; const B: Int32): Integer;
function HugeWordCompareInt64(const A: HugeWord; const B: Int64): Integer;
function HugeWordCompare(const A, B: HugeWord): Integer;
procedure HugeWordMin(var A: HugeWord; const B: HugeWord);
procedure HugeWordMax(var A: HugeWord; const B: HugeWord);
function HugeWordGetBitCount(const A: HugeWord): Integer;
procedure HugeWordSetBitCount(var A: HugeWord; const Bits: Integer);
function HugeWordIsBitSet(const A: HugeWord; const B: Integer): Boolean;
procedure HugeWordSetBit(var A: HugeWord; const B: Integer);
procedure HugeWordSetBit0(var A: HugeWord); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordClearBit(var A: HugeWord; const B: Integer);
procedure HugeWordToggleBit(var A: HugeWord; const B: Integer);
function HugeWordSetBitScanForward(const A: HugeWord): Integer;
function HugeWordSetBitScanReverse(const A: HugeWord): Integer;
function HugeWordClearBitScanForward(const A: HugeWord): Integer;
function HugeWordClearBitScanReverse(const A: HugeWord): Integer;
procedure HugeWordShl(var A: HugeWord; const B: Integer);
procedure HugeWordShl1(var A: HugeWord);
procedure HugeWordShr(var A: HugeWord; const B: Integer);
procedure HugeWordShr1(var A: HugeWord);
procedure HugeWordNot(var A: HugeWord);
procedure HugeWordOrHugeWord(var A: HugeWord; const B: HugeWord);
procedure HugeWordAndHugeWord(var A: HugeWord; const B: HugeWord);
procedure HugeWordXorHugeWord(var A: HugeWord; const B: HugeWord);
procedure HugeWordAddWord32(var A: HugeWord; const B: Word32);
procedure HugeWordAdd(var A: HugeWord; const B: HugeWord);
procedure HugeWordInc(var A: HugeWord);
function HugeWordSubtractWord32(var A: HugeWord; const B: Word32): Integer;
function HugeWordSubtract(var A: HugeWord; const B: HugeWord): Integer;
procedure HugeWordDec(var A: HugeWord);
procedure HugeWordMultiplyWord8(var A: HugeWord; const B: Byte);
procedure HugeWordMultiplyWord16(var A: HugeWord; const B: Word);
procedure HugeWordMultiplyWord32(var A: HugeWord; const B: Word32);
procedure HugeWordMultiply_Long_NN_Unsafe(var Res: HugeWord; const A, B: HugeWord);
procedure HugeWordMultiply_Long_NN_Safe(var Res: HugeWord; const A, B: HugeWord);
procedure HugeWordMultiply_Long_NN(var Res: HugeWord; const A, B: HugeWord);
procedure HugeWordMultiply_Long(var Res: HugeWord; const A, B: HugeWord);
procedure HugeWordMultiply_ShiftAdd(var Res: HugeWord; const A, B: HugeWord);
procedure HugeWordMultiply(var Res: HugeWord; const A, B: HugeWord); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeWordSqr(var Res: HugeWord; const A: HugeWord);
procedure HugeWordDivideWord32(const A: HugeWord; const B: Word32; var Q: HugeWord; out R: Word32);
procedure HugeWordDivide_RR_Unsafe(const A, B: HugeWord; var Q, R: HugeWord);
procedure HugeWordDivide_RR_Safe(const A, B: HugeWord; var Q, R: HugeWord);
procedure HugeWordDivide(const A, B: HugeWord; var Q, R: HugeWord);
procedure HugeWordMod(const A, B: HugeWord; var R: HugeWord);
procedure HugeWordGCD(const A, B: HugeWord; var R: HugeWord);
procedure HugeWordPower(var A: HugeWord; const B: Word32);
procedure HugeWordPowerAndMod(var Res: HugeWord; const A, E, M: HugeWord);
function HugeWordToStrB(const A: HugeWord): UTF8String;
function HugeWordToStrU(const A: HugeWord): UnicodeString;
function HugeWordToStr(const A: HugeWord): String;
procedure StrToHugeWordB(const A: RawByteString; var R: HugeWord);
procedure StrToHugeWordU(const A: UnicodeString; var R: HugeWord);
procedure StrToHugeWord(const A: String; var R: HugeWord);
function HugeWordToHexB(const A: HugeWord; const LowCase: Boolean = False): UTF8String;
function HugeWordToHex(const A: HugeWord; const LowCase: Boolean = False): String;
procedure HexToHugeWordB(const A: RawByteString; var R: HugeWord);
procedure HexToHugeWord(const A: String; var R: HugeWord);
procedure HugeWordISqrt(var A: HugeWord);
procedure HugeWordExtendedEuclid(const A, B: HugeWord; var R: HugeWord; var X, Y: HugeInt);
function HugeWordModInv(const E, M: HugeWord; var R: HugeWord): Boolean;
procedure HugeWordRandom(var A: HugeWord; const Size: Integer);
procedure HugeWordRandomN(var A: HugeWord; const N: HugeWord);
type
TPrimality = (
pPotentialPrime,
pNotPrime,
pPrime);
function HugeWordIsPrime_QuickTrial(const A: HugeWord): TPrimality;
function HugeWordIsPrime_MillerRabin(const A: HugeWord): TPrimality;
function HugeWordIsPrime(const A: HugeWord): TPrimality;
procedure HugeWordNextPotentialPrime(var A: HugeWord;
const CallbackProc: THugeWordCallbackProc = nil;
const CallbackData: Integer = 0);
{ }
{ HugeInt }
{ }
procedure HugeIntInit(out A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntFinalise(var A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntClearAndFinalise(var A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntNormalise(var A: HugeInt);
procedure HugeIntInitZero(out A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntInitOne(out A: HugeInt);
procedure HugeIntInitMinusOne(out A: HugeInt);
procedure HugeIntInitWord32(out A: HugeInt; const B: Word32);
procedure HugeIntInitInt32(out A: HugeInt; const B: Int32);
procedure HugeIntInitInt64(out A: HugeInt; const B: Int64);
procedure HugeIntInitDouble(out A: HugeInt; const B: Double);
procedure HugeIntInitHugeWord(out A: HugeInt; const B: HugeWord);
procedure HugeIntInitHugeInt(out A: HugeInt; const B: HugeInt);
procedure HugeIntAssignZero(var A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntAssignOne(var A: HugeInt);
procedure HugeIntAssignMinusOne(var A: HugeInt);
procedure HugeIntAssignWord32(var A: HugeInt; const B: Word32);
procedure HugeIntAssignInt32(var A: HugeInt; const B: Int32);
procedure HugeIntAssignInt64(var A: HugeInt; const B: Int64);
procedure HugeIntAssignDouble(var A: HugeInt; const B: Double);
procedure HugeIntAssignHugeWord(var A: HugeInt; const B: HugeWord);
procedure HugeIntAssignHugeWordNegated(var A: HugeInt; const B: HugeWord);
procedure HugeIntAssign(var A: HugeInt; const B: HugeInt);
procedure HugeIntSwap(var A, B: HugeInt);
function HugeIntIsZero(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsNegative(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsNegativeOrZero(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsPositive(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsPositiveOrZero(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsOne(const A: HugeInt): Boolean;
function HugeIntIsMinusOne(const A: HugeInt): Boolean;
function HugeIntIsOdd(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsEven(const A: HugeInt): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntIsWord32Range(const A: HugeInt): Boolean;
function HugeIntIsWord64Range(const A: HugeInt): Boolean;
function HugeIntIsWord128Range(const A: HugeInt): Boolean;
function HugeIntIsWord256Range(const A: HugeInt): Boolean;
function HugeIntIsInt32Range(const A: HugeInt): Boolean;
function HugeIntIsInt64Range(const A: HugeInt): Boolean;
function HugeIntIsInt128Range(const A: HugeInt): Boolean;
function HugeIntIsInt256Range(const A: HugeInt): Boolean;
function HugeIntSign(const A: HugeInt): Integer; {$IFDEF UseInline}inline;{$ENDIF}
procedure HugeIntNegate(var A: HugeInt); {$IFDEF UseInline}inline;{$ENDIF}
function HugeIntAbsInPlace(var A: HugeInt): Boolean;
function HugeIntAbs(const A: HugeInt; var B: HugeWord): Boolean;
function HugeIntToWord32(const A: HugeInt): Word32;
function HugeIntToInt32(const A: HugeInt): Int32;
function HugeIntToInt64(const A: HugeInt): Int64;
function HugeIntToDouble(const A: HugeInt): Double;
function HugeIntEqualsWord32(const A: HugeInt; const B: Word32): Boolean;
function HugeIntEqualsInt32(const A: HugeInt; const B: Int32): Boolean;
function HugeIntEqualsInt64(const A: HugeInt; const B: Int64): Boolean;
function HugeIntEqualsHugeInt(const A, B: HugeInt): Boolean;
function HugeIntCompareWord32(const A: HugeInt; const B: Word32): Integer;
function HugeIntCompareInt32(const A: HugeInt; const B: Int32): Integer;
function HugeIntCompareInt64(const A: HugeInt; const B: Int64): Integer;
function HugeIntCompareHugeInt(const A, B: HugeInt): Integer;
function HugeIntCompareHugeIntAbs(const A, B: HugeInt): Integer;
procedure HugeIntMin(var A: HugeInt; const B: HugeInt);
procedure HugeIntMax(var A: HugeInt; const B: HugeInt);
procedure HugeIntAddWord32(var A: HugeInt; const B: Word32);
procedure HugeIntAddInt32(var A: HugeInt; const B: Int32);
procedure HugeIntAddHugeInt(var A: HugeInt; const B: HugeInt);
procedure HugeIntInc(var A: HugeInt);
procedure HugeIntSubtractWord32(var A: HugeInt; const B: Word32);
procedure HugeIntSubtractInt32(var A: HugeInt; const B: Int32);
procedure HugeIntSubtractHugeInt(var A: HugeInt; const B: HugeInt);
procedure HugeIntDec(var A: HugeInt);
procedure HugeIntMultiplyWord8(var A: HugeInt; const B: Byte);
procedure HugeIntMultiplyWord16(var A: HugeInt; const B: Word);
procedure HugeIntMultiplyWord32(var A: HugeInt; const B: Word32);
procedure HugeIntMultiplyInt8(var A: HugeInt; const B: ShortInt);
procedure HugeIntMultiplyInt16(var A: HugeInt; const B: SmallInt);
procedure HugeIntMultiplyInt32(var A: HugeInt; const B: Int32);
procedure HugeIntMultiplyHugeWord(var A: HugeInt; const B: HugeWord);
procedure HugeIntMultiplyHugeInt(var A: HugeInt; const B: HugeInt);
procedure HugeIntSqr(var A: HugeInt);
procedure HugeIntDivideWord32(const A: HugeInt; const B: Word32; var Q: HugeInt; out R: Word32);
procedure HugeIntDivideInt32(const A: HugeInt; const B: Int32; var Q: HugeInt; out R: Int32);
procedure HugeIntDivideHugeInt_T(const A, B: HugeInt; var Q, R: HugeInt);
procedure HugeIntDivideHugeInt_F(const A, B: HugeInt; var Q, R: HugeInt);
procedure HugeIntDivideHugeInt_E(const A, B: HugeInt; var Q, R: HugeInt);
procedure HugeIntDivideHugeInt(const A, B: HugeInt; var Q, R: HugeInt);
procedure HugeIntMod_T(const A, B: HugeInt; var R: HugeInt);
procedure HugeIntMod_F(const A, B: HugeInt; var R: HugeInt);
procedure HugeIntMod_E(const A, B: HugeInt; var R: HugeInt);
procedure HugeIntMod(const A, B: HugeInt; var R: HugeInt);
procedure HugeIntPower(var A: HugeInt; const B: Word32);
function HugeIntToStrB(const A: HugeInt): UTF8String;
function HugeIntToStrU(const A: HugeInt): UnicodeString;
procedure StrToHugeIntB(const A: RawByteString; var R: HugeInt);
procedure StrToHugeIntU(const A: UnicodeString; var R: HugeInt);
function HugeIntToHexB(const A: HugeInt): UTF8String;
procedure HexToHugeIntB(const A: RawByteString; var R: HugeInt);
procedure HugeIntISqrt(var A: HugeInt);
procedure HugeIntRandom(var A: HugeInt; const Size: Integer);
{ }
{ HugeInt class }
{ }
type
THugeInt = class
private
FValue : HugeInt;
public
constructor Create; overload;
constructor Create(const A: Int64); overload;
constructor Create(const A: THugeInt); overload;
destructor Destroy; override;
procedure AssignZero;
procedure AssignOne;
procedure AssignMinusOne;
procedure Assign(const A: Int64); overload;
procedure Assign(const A: THugeInt); overload;
function IsZero: Boolean;
function IsNegative: Boolean;
function IsPositive: Boolean;
function IsOne: Boolean;
function IsMinusOne: Boolean;
function IsOdd: Boolean;
function IsEven: Boolean;
function Sign: Integer;
procedure Negate;
procedure Abs;
function ToWord32: Word32;
function ToInt32: Int32;
function ToInt64: Int64;
function EqualTo(const A: Word32): Boolean; overload;
function EqualTo(const A: Int32): Boolean; overload;
function EqualTo(const A: Int64): Boolean; overload;
function EqualTo(const A: THugeInt): Boolean; overload;
function Compare(const A: Word32): Integer; overload;
function Compare(const A: Int32): Integer; overload;
function Compare(const A: Int64): Integer; overload;
function Compare(const A: THugeInt): Integer; overload;
procedure Add(const A: Int32); overload;
procedure Add(const A: THugeInt); overload;
procedure Inc;
procedure Subtract(const A: Int32); overload;
procedure Subtract(const A: THugeInt); overload;
procedure Dec;
procedure Multiply(const A: Int32); overload;
procedure Multiply(const A: THugeInt); overload;
procedure Sqr;
procedure Divide(const B: Int32; out R: Int32); overload;
procedure Divide(const B: THugeInt; var R: THugeInt); overload;
procedure Power(const B: Word32);
function ToStr: UTF8String;
function ToHex: UTF8String;
procedure AssignStr(const A: RawByteString);
procedure AssignHex(const A: RawByteString);
procedure ISqrt;
procedure Random(const Size: Integer);
end;
{ }
{ Test cases }
{ }
{$IFDEF HUGEINT_TEST}
procedure Test;
{$ENDIF}
{$IFDEF HUGEINT_PROFILE}
procedure Profile;
{$ENDIF}
implementation
uses
{ System }
{$IFDEF HUGEINT_PROFILE}
Windows,
{$ENDIF}
{ Fundamentals }
flcRandom;
{ }
{ Utilities }
{ }
const
BitMaskTable32: array[0..31] of Word32 =
($00000001, $00000002, $00000004, $00000008,
$00000010, $00000020, $00000040, $00000080,
$00000100, $00000200, $00000400, $00000800,
$00001000, $00002000, $00004000, $00008000,
$00010000, $00020000, $00040000, $00080000,
$00100000, $00200000, $00400000, $00800000,
$01000000, $02000000, $04000000, $08000000,
$10000000, $20000000, $40000000, $80000000);
{$IFDEF SupportUInt64}
{$IFDEF CPU_64}
{$DEFINE Pas64}
{$ENDIF}
{$ENDIF}
{$IFDEF DELPHI}
{$IFDEF CPU_X86_64}
{$IFNDEF PurePascal}
{$DEFINE Asm64}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF Pas64}
{$IFDEF FREEPASCAL}
type
PUInt64 = ^UInt64;
{$ENDIF}
{$ENDIF}
{ }
{ Error routines }
{ }
const
SDivByZeroError = 'Division by zero';
SRangeError = 'Range error';
SConvertError = 'Conversion error';
SInvalidOpError = 'Invalid operation';
procedure RaiseDivByZeroError; {$IFDEF UseInline}inline;{$ENDIF}
begin
raise EHugeIntDivByZero.Create(SDivByZeroError);
end;
procedure RaiseRangeError; {$IFDEF UseInline}inline;{$ENDIF}
begin
raise EHugeIntRangeError.Create(SRangeError);
end;
procedure RaiseConvertError; {$IFDEF UseInline}inline;{$ENDIF}
begin
raise EHugeIntConvertError.Create(SConvertError);
end;
procedure RaiseInvalidOpError; {$IFDEF UseInline}inline;{$ENDIF}
begin
raise EHugeIntInvalidOp.Create(SInvalidOpError);
end;
{ }
{ HugeWord }
{ }
{ HugeWord Init }
{ HugeWordInit needs to be called on every instance of HugeWord (except }
{ where it can be assured the HugeWord structure is zero) before using it }
{ in calls to other HugeWord routines. }
{ Every HugeWord instance must be finalised with a call to HugeWordFinalise. }
procedure HugeWordInit(out A: HugeWord);
begin
A.Used := 0;
A.Alloc := 0;
A.Data := @A.InitBuf;
end;
{ HugeWord Alloc }
{ Post: HugeWord data is undefined. }
procedure HugeWordAlloc(var A: HugeWord; const Size: Integer);
var L : Integer;
begin
Assert(Size > 0);
L := Size * HugeWordElementSize;
GetMem(A.Data, L);
A.Alloc := Size;
end;
{ HugeWord AllocZero }
{ Post: HugeWord data is zero. }
procedure HugeWordAllocZero(var A: HugeWord; const Size: Integer);
var L : Integer;
begin
Assert(Size > 0);
L := Size * HugeWordElementSize;
GetMem(A.Data, L);
A.Alloc := Size;
FillChar(A.Data^, L, 0);
end;
{ HugeWord Free }
procedure HugeWordFree(var A: HugeWord);
begin
Assert(A.Alloc > 0);
Assert(A.Data <> nil);
FreeMem(A.Data);
A.Alloc := 0;
A.Data := @A.InitBuf;
A.Used := 0;
end;
{ HugeWord Realloc }
{ Post: If expanding, expanded HugeWord data is not zerod. }
procedure HugeWordRealloc(var A: HugeWord; const Size: Integer);
var OldSize, L : Integer;
begin
Assert(Size >= 0);
OldSize := A.Alloc;
if OldSize = Size then
exit;
if Size <= 0 then
begin
HugeWordFree(A);
exit;
end;
if OldSize = 0 then
begin
HugeWordAlloc(A, Size);
exit;
end;
L := Size * HugeWordElementSize;
ReallocMem(A.Data, L);
A.Alloc := Size;
end;
{ HugeWord Finalise }
{ Release resources allocated by the HugeWord. }
procedure HugeWordFinalise(var A: HugeWord);
begin
if A.Alloc > 0 then
HugeWordFree(A);
end;
{ HugeWord Clear And Finalise }
{ Clear used data before finalising HugeWord. }
procedure HugeWordClearAndFinalise(var A: HugeWord);
begin
if Assigned(A.Data) then
begin
if A.Used > 0 then
FillChar(A.Data^, A.Used, 0);
if A.Data <> @A.InitBuf then
FillChar(A.InitBuf, SizeOf(A.InitBuf), 0);
end;
HugeWordFinalise(A);
end;
{ HugeWord GetSize }
{ Post: Returns number of HugeWordItems in the HugeWord structure. }
function HugeWordGetSize(const A: HugeWord): Integer;
begin
Result := A.Used;
end;
{ HugeWord GetSizeInBits }
{ Post: Returns number of bits in the HugeWord structure. }
function HugeWordGetSizeInBits(const A: HugeWord): Integer;
begin
Result := A.Used * HugeWordElementBits;
end;
{ HugeWord SetSize NoZeroMem }
{ Post: Expanded data is not set to zero. }
procedure HugeWordSetSize_NoZeroMem(var A: HugeWord; const Size: Integer);
var OldUsed, OldAlloc, NewAlloc : Integer;
begin
Assert(Size >= 0);
OldUsed := A.Used;
if Size = OldUsed then // unchanged
exit;
if Size < OldUsed then
begin
// shrink: keep allocated memory
A.Used := Size;
exit;
end;
// expand
OldAlloc := A.Alloc;
if OldAlloc = 0 then
begin
// no dynamic memory allocated
if Size <= HugeWordStaticBufferSize then
begin
// fits in static buffer
A.Used := Size;
exit;
end;
// first dynamic allocation
HugeWordAlloc(A, Size);
if OldUsed > 0 then
Move(A.InitBuf[0], A.Data^, OldUsed * HugeWordElementSize);
A.Used := Size;
exit;
end;
if Size > OldAlloc then
begin
// expanding block: allocate more memory than requested, this reduces
// the number of future Realloc calls
NewAlloc := OldAlloc * 2;
if NewAlloc < Size then
NewAlloc := Size;
HugeWordRealloc(A, NewAlloc);
end;
A.Used := Size;
end;
{ HugeWord SetSize }
{ Post: Expanded data is set to zero. }
procedure HugeWordSetSize(var A: HugeWord; const Size: Integer);
var OldUsed, OldAlloc, NewAlloc : Integer;
P : PByte;
begin
Assert(Size >= 0);
OldUsed := A.Used;
if Size = OldUsed then // unchanged
exit;
if Size < OldUsed then
begin
// shrink: keep allocated memory
A.Used := Size;
exit;
end;
// expand
OldAlloc := A.Alloc;
if OldAlloc = 0 then
begin
// no dynamic memory allocated
if Size <= HugeWordStaticBufferSize then
begin
// fits in static buffer
FillChar(A.InitBuf[OldUsed], (Size - OldUsed) * HugeWordElementSize, 0);
A.Used := Size;
exit;
end;
// first dynamic allocation
HugeWordAlloc(A, Size);
if OldUsed > 0 then
Move(A.InitBuf[0], A.Data^, OldUsed * HugeWordElementSize);
end
else
if Size > OldAlloc then
begin
// expanding block: allocate more memory than requested, this reduces
// the number of future Realloc calls
NewAlloc := OldAlloc * 2;
if NewAlloc < Size then
NewAlloc := Size;
HugeWordRealloc(A, NewAlloc);
end;
// set expanded elements to zero
P := A.Data;
Inc(P, OldUsed * HugeWordElementSize);
FillChar(P^, (Size - OldUsed) * HugeWordElementSize, 0);
A.Used := Size;
end;
{ HugeWord SetSizeInBits }
{ Post: Expanded data is set to zero. }
{ Size in bits is multiple of HugeWordElementBits. }
procedure HugeWordSetSizeInBits(var A: HugeWord; const Size: Integer);
begin
Assert(Size >= 0);
HugeWordSetSize(A, (Size + HugeWordElementBits - 1) div HugeWordElementBits);
end;
{ HugeWord GetElement }
{ Pre: Index is 0 based }
function HugeWordGetElement(const A: HugeWord; const I: Integer): Word32;
var P : PWord32;
begin
Assert(I < A.Used);
Assert(I >= 0);
P := A.Data;
Inc(P, I);
Result := P^;
end;
procedure HugeWordSetElement(const A: HugeWord; const I: Integer; const B: Word32);
var P : PWord32;
begin
Assert(I < A.Used);
Assert(I >= 0);
P := A.Data;
Inc(P, I);
P^ := B;
end;
function HugeWordGetFirstElementPtr(const A: HugeWord): PHugeWordElement;
begin
if A.Used = 0 then
Result := nil
else
Result := A.Data;
end;
function HugeWordGetLastElementPtr(const A: HugeWord): PHugeWordElement;
var L : Integer;
begin
L := A.Used;
if L = 0 then
Result := nil
else
begin
Result := A.Data;
Inc(Result, L - 1);
end;
end;
{ HugeWord Normalise (helper function) }
{ A 'normalised' HugeWord has no trailing zeros (ie the most significant }
{ value is non-zero) or it is nil (to represent a value of 0). }
procedure HugeWordNormalise(var A: HugeWord);
var I, L : Integer;
P : PWord32;
begin
L := A.Used;
if L = 0 then
exit;
I := 0;
P := A.Data;
Inc(P, L - 1);
while (I < L) and (P^ = 0) do
begin
Dec(P);
Inc(I);
end;
if I = 0 then
exit;
HugeWordSetSize(A, L - I);
end;
{ HugeWord Init Zero }
{ Post: A is zero }
{ A normalised }
procedure HugeWordInitZero(out A: HugeWord);
begin
HugeWordInit(A);
end;
{ HugeWord Init One }
{ Post: A is zero }
{ A normalised }
procedure HugeWordInitOne(out A: HugeWord);
begin
HugeWordInit(A);
HugeWordAssignOne(A);
end;
procedure HugeWordInitWord32(out A: HugeWord; const B: Word32);
begin
HugeWordInit(A);
HugeWordAssignWord32(A, B);
end;
procedure HugeWordInitInt32(out A: HugeWord; const B: Int32);
begin
HugeWordInit(A);
HugeWordAssignInt32(A, B);
end;
procedure HugeWordInitInt64(out A: HugeWord; const B: Int64);
begin
HugeWordInit(A);
HugeWordAssignInt64(A, B);
end;
procedure HugeWordInitDouble(out A: HugeWord; const B: Double);
begin
HugeWordInit(A);
HugeWordAssignDouble(A, B);
end;
procedure HugeWordInitHugeWord(out A: HugeWord; const B: HugeWord);
var L : Integer;
begin
HugeWordInit(A);
L := B.Used;
if L = 0 then
exit;
HugeWordSetSize(A, L);
Move(B.Data^, A.Data^, L * HugeWordElementSize);
end;
procedure HugeWordAssignZero(var A: HugeWord);
begin
HugeWordSetSize(A, 0);
end;
procedure HugeWordAssignOne(var A: HugeWord);
begin
HugeWordSetSize_NoZeroMem(A, 1);
PWord32(A.Data)^ := 1;
end;
procedure HugeWordAssignWord32(var A: HugeWord; const B: Word32);
begin
if B = 0 then
HugeWordAssignZero(A)
else
begin
HugeWordSetSize_NoZeroMem(A, 1);
PWord32(A.Data)^ := B;
end;
end;
procedure HugeWordAssignInt32(var A: HugeWord; const B: Int32);
begin
{$IFOPT R+}
if B < 0 then
RaiseRangeError else
{$ENDIF}
if B = 0 then
HugeWordAssignZero(A)
else
begin
HugeWordSetSize_NoZeroMem(A, 1);
PWord32(A.Data)^ := Word32(B);
end;
end;
{ HugeWord AssignInt64 }
{ Post: A normalised }
procedure HugeWordAssignInt64(var A: HugeWord; const B: Int64);
var P : PWord32;
begin
{$IFOPT R+}
if B < 0 then
RaiseRangeError else
{$ENDIF}
if Int64Rec(B).Hi = 0 then
HugeWordAssignWord32(A, Int64Rec(B).Lo)
else
begin
HugeWordSetSize_NoZeroMem(A, 2);
P := A.Data;
P^ := Int64Rec(B).Lo;
Inc(P);
P^ := Int64Rec(B).Hi;
HugeWordNormalise(A);
end;
end;
procedure HugeWordAssignDouble(var A: HugeWord; const B: Double);
var C, D, E : Double;
V : Word32;
L, I : Integer;
P : PWord32;
begin
if Abs(Frac(B)) > 1.0E-10 then
RaiseConvertError;
if B < -1.0E-10 then
RaiseConvertError;
L := 0;
C := Abs(B);
while C >= 1.0 do
begin
C := C / 4294967296.0;
Inc(L);
end;
HugeWordSetSize(A, L);
if L = 0 then
exit;
P := A.Data;
C := Abs(B);
for I := 0 to L - 1 do
begin
D := C / 4294967296.0;
E := C - Trunc(D) * 4294967296.0;
V := Word32(Trunc(E));
P^ := V;
Inc(P);
C := D;
end;
end;
procedure HugeWordAssign(var A: HugeWord; const B: HugeWord);
var L : Integer;
begin
L := B.Used;
HugeWordSetSize_NoZeroMem(A, L);
if L = 0 then
exit;
Move(B.Data^, A.Data^, L * HugeWordElementSize);
end;
{ HugeWord Assign HugeInt Abs }
procedure HugeWordAssignHugeIntAbs(var A: HugeWord; const B: HugeInt);
begin
if B.Sign = 0 then
HugeWordAssignZero(A)
else
HugeWordAssign(A, B.Value);
end;
procedure HugeWordAssignBuf(var A: HugeWord; const Buf; const BufSize: Integer;
const ReverseByteOrder: Boolean);
var L, I : Integer;
P, Q : PByte;
begin
if BufSize <= 0 then
HugeWordAssignZero(A)
else
begin
L := (BufSize + HugeWordElementSize - 1) div HugeWordElementSize;
HugeWordSetSize_NoZeroMem(A, L);
P := @Buf;
Q := A.Data;
if ReverseByteOrder then
Inc(P, BufSize - 1);
for I := 0 to BufSize - 1 do
begin
Q^ := P^;
Inc(Q);
if ReverseByteOrder then
Dec(P)
else
Inc(P);
end;
for I := 0 to BufSize mod 4 - 1 do
begin
Q^ := 0;
Inc(Q);
end;
end;
end;
procedure HugeWordAssignBufStrB(var A: HugeWord; const Buf: RawByteString;
const ReverseByteOrder: Boolean);
var L : Integer;
begin
L := Length(Buf);
if L = 0 then
HugeWordAssignZero(A)
else
HugeWordAssignBuf(A, Buf[1], L, ReverseByteOrder);
end;
procedure HugeWordSwap(var A, B: HugeWord);
var C : HugeWord;
begin
HugeWordInitHugeWord(C, A); // C := A
try
HugeWordAssign(A, B); // A := B
HugeWordAssign(B, C); // B := C
finally
HugeWordFinalise(C);
end;
end;
{ HugeWord IsZero }
{ Pre: A normalised }
{ Post: Result is True if A is zero }
function HugeWordIsZero(const A: HugeWord): Boolean;
begin
Result := A.Used = 0;
end;
{ HugeWord IsOne }
{ Pre: A normalised }
{ Post: Result is True if A is one }
function HugeWordIsOne(const A: HugeWord): Boolean;
begin
if A.Used <> 1 then
Result := False
else
Result := PWord32(A.Data)^ = 1;
end;
{ HugeWord IsTwo }
{ Pre: A normalised }
{ Post: Result is True if A is two }
function HugeWordIsTwo(const A: HugeWord): Boolean;
begin
if A.Used <> 1 then
Result := False
else
Result := PWord32(A.Data)^ = 2;
end;
{ HugeWord IsOdd }
{ Pre: A normalised }
{ Post: Result is True if A is odd }
function HugeWordIsOdd(const A: HugeWord): Boolean;
begin
if A.Used = 0 then
Result := False
else
Result := PWord32(A.Data)^ and 1 = 1;
end;
{ HugeWord IsEven }
{ Pre: A normalised }
{ Post: Result is True if A is even (zero is even) }
function HugeWordIsEven(const A: HugeWord): Boolean;
begin
if A.Used = 0 then
Result := True
else
Result := PWord32(A.Data)^ and 1 = 0;
end;
{ HugeWord Word32 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in 32-bit word range }
function HugeWordIsWord32Range(const A: HugeWord): Boolean;
begin
Result := (A.Used <= 1);
end;
{ HugeWord Word64 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in 64-bit word range }
function HugeWordIsWord64Range(const A: HugeWord): Boolean;
begin
Result := (A.Used <= 2);
end;
{ HugeWord Word128 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in 128-bit word range }
function HugeWordIsWord128Range(const A: HugeWord): Boolean;
begin
Result := (A.Used <= 4);
end;
{ HugeWord Word256 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in 128-bit word range }
function HugeWordIsWord256Range(const A: HugeWord): Boolean;
begin
Result := (A.Used <= 8);
end;
{ HugeWord Int32 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in Int32 range }
function HugeWordIsInt32Range(const A: HugeWord): Boolean;
var L : Integer;
begin
L := A.Used;
if L = 0 then
Result := True else
if L > 1 then
Result := False
else
Result := PWord32(A.Data)^ < $80000000;
end;
{ HugeWord Int64 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in Int64 range }
function HugeWordIsInt64Range(const A: HugeWord): Boolean;
var L : Integer;
P : PWord32;
begin
L := A.Used;
if L <= 1 then
Result := True else
if L > 2 then
Result := False
else
begin
P := A.Data;
Inc(P);
Result := P^ < $80000000;
end;
end;
{ HugeWord Int128 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in Int128 range }
function HugeWordIsInt128Range(const A: HugeWord): Boolean;
var L : Integer;
P : PWord32;
begin
L := A.Used;
if L <= 1 then
Result := True else
if L > 4 then
Result := False
else
begin
P := A.Data;
Inc(P, 3);
Result := P^ < $80000000;
end;
end;
{ HugeWord Int256 range checking }
{ Pre: A normalised }
{ Post: Result is True if A is in Int256 range }
function HugeWordIsInt256Range(const A: HugeWord): Boolean;
var L : Integer;
P : PWord32;
begin
L := A.Used;
if L <= 1 then
Result := True else
if L > 8 then
Result := False
else
begin
P := A.Data;
Inc(P, 7);
Result := P^ < $80000000;
end;
end;
function HugeWordToWord32(const A: HugeWord): Word32;
var L : Integer;
begin
L := A.Used;
{$IFOPT R+}
if L > 1 then
RaiseRangeError;
{$ENDIF};
if L = 0 then
Result := 0
else
Result := PWord32(A.Data)^;
end;
function HugeWordToInt32(const A: HugeWord): Int32;
var L : Integer;
begin
L := A.Used;
{$IFOPT R+}
if L > 1 then
RaiseRangeError;
if L > 0 then
if PWord32(A.Data)^ >= $80000000 then
RaiseRangeError;
{$ENDIF};
if L = 0 then
Result := 0
else
Result := PInt32(A.Data)^;
end;
function HugeWordToInt64(const A: HugeWord): Int64;
var L : Integer;
P : PWord32;
begin
L := A.Used;
if L = 0 then
begin
Result := 0;
exit;
end;
if L = 1 then
begin
Result := PWord32(A.Data)^;
exit;
end;
{$IFOPT R+}
if L > 2 then
RaiseRangeError;
if L > 1 then
begin
P := A.Data;
Inc(P);
if P^ >= $80000000 then
RaiseRangeError;
end;
{$ENDIF};
P := A.Data;
Int64Rec(Result).Lo := P^;
Inc(P);
Int64Rec(Result).Hi := P^;
end;
function HugeWordToDouble(const A: HugeWord): Double;
var L, I : Integer;
P : PWord32;
R, F, T : Double;
{$IFOPT R+}
const
MaxF = 1.7E+308 / 4294967296.0 / 4294967296.0;
{$ENDIF}
begin
L := A.Used;
if L = 0 then
begin
Result := 0.0;
exit;
end;
P := A.Data;
R := P^;
F := 1.0;
for I := 0 to L - 2 do
begin
Inc(P);
F := F * 4294967296.0;
{$IFOPT R+}
if F >= MaxF then
RaiseRangeError;
{$ENDIF}
T := P^;
R := R + F * T;
end;
Result := R;
end;
{ HugeWord equals Word }
{ Pre: A normalised }
function HugeWordEqualsWord32(const A: HugeWord; const B: Word32): Boolean;
var L : Integer;
begin
L := A.Used;
if L = 0 then
Result := (B = 0) else
if L = 1 then
Result := (B = PWord32(A.Data)^)
else
Result := False;
end;
{ HugeWord equals Int }
{ Pre: A normalised }
function HugeWordEqualsInt32(const A: HugeWord; const B: Int32): Boolean;
var L : Integer;
begin
if B < 0 then
Result := False
else
begin
L := A.Used;
if L = 0 then
Result := (B = 0) else
if L = 1 then
Result := (PWord32(A.Data)^ = Word32(B))
else
Result := False;
end;
end;
function HugeWordEqualsInt64(const A: HugeWord; const B: Int64): Boolean;
var L : Integer;
P : PWord32;
begin
if B < 0 then
Result := False
else
begin
L := A.Used;
if L = 0 then
Result := (B = 0) else
if L = 1 then
Result := (PWord32(A.Data)^ = B) else
if L = 2 then
begin
P := A.Data;
Result := P^ = Int64Rec(B).Lo;
if not Result then
exit;
Inc(P);
Result := P^ = Int64Rec(B).Hi;
end
else
Result := False;
end;
end;
{ HugeWord equals }
{ Pre: A and B normalised }
{$IFDEF Pas64}
function HugeWordEquals(const A, B: HugeWord): Boolean;
var L, M, I : Integer;
P, Q : PWord32;
T, U : PUInt64;
begin
L := A.Used;
M := B.Used;
if L <> M then
begin
Result := False;
exit;
end;
P := A.Data;
Q := B.Data;
if P = Q then
begin
Result := True;
exit;
end;
T := Pointer(P);
U := Pointer(Q);
for I := 0 to (L div 2) - 1 do
begin
if T^ <> U^ then
begin
Result := False;
exit;
end;
Inc(T);
Inc(U);
end;
if L and 1 <> 0 then
begin
P := Pointer(T);
Q := Pointer(U);
if P^ <> Q^ then
begin
Result := False;
exit;
end;
end;
Result := True;
end;
{$ELSE}
function HugeWordEquals(const A, B: HugeWord): Boolean;
var L, M, I : Integer;
P, Q : PWord32;
begin
L := A.Used;
M := B.Used;
if L <> M then
begin
Result := False;
exit;
end;
P := A.Data;
Q := B.Data;
if P = Q then
begin
Result := True;
exit;
end;
for I := 0 to L - 1 do
if P^ <> Q^ then
begin
Result := False;
exit;
end
else
begin
Inc(P);
Inc(Q);
end;
Result := True;
end;
{$ENDIF}
{ HugeWord Compare Word }
{ Pre: A normalised }
{ Post: Result is -1 if A < B, 1 if A > B or 0 if A = B }
function HugeWordCompareWord32(const A: HugeWord; const B: Word32): Integer;
var L : Integer;
F : Word32;
begin
L := A.Used;
if L = 0 then
begin
if B = 0 then
Result := 0
else
Result := -1;
exit;
end;
if L > 1 then
begin
Result := 1;
exit;
end;
F := PWord32(A.Data)^;
if F < B then
Result := -1 else
if F > B then
Result := 1
else
Result := 0;
end;
{ HugeWord Compare Int }
{ Pre: A normalised }
{ Post: Result is -1 if A < B, 1 if A > B or 0 if A = B }
function HugeWordCompareInt32(const A: HugeWord; const B: Int32): Integer;
var L : Integer;
F : Word32;
begin
if B < 0 then
begin
Result := 1;
exit;
end;
L := A.Used;
if L = 0 then
begin
if B = 0 then
Result := 0
else
Result := -1;
exit;
end;
if L > 1 then
begin
Result := 1;
exit;
end;
F := PWord32(A.Data)^;
if F < Word32(B) then
Result := -1 else
if F > Word32(B) then
Result := 1
else
Result := 0;
end;
function HugeWordCompareInt64(const A: HugeWord; const B: Int64): Integer;
var L : Integer;
F, G : Word32;
P : PWord32;
begin
if B < 0 then
begin
Result := 1;
exit;
end;
L := A.Used;
case L of
0 : begin
if B = 0 then
Result := 0
else
Result := -1;
exit;
end;
1 : if Int64Rec(B).Hi = 0 then
begin
F := PWord32(A.Data)^;
G := Int64Rec(B).Lo;
end
else
begin
Result := -1;
exit;
end;
2 : begin
P := A.Data;
Inc(P);
F := P^;
G := Int64Rec(B).Hi;
if F = G then
begin
F := PWord32(A.Data)^;
G := Int64Rec(B).Lo;
end;
end;
else
begin
Result := 1;
exit;
end;
end;
if F < G then
Result := -1 else
if F > G then
Result := 1
else
Result := 0;
end;
{ HugeWord Compare }
{ Pre: A and B normalised }
{ Post: Result is -1 if A < B, 1 if A > B or 0 if A = B }
{$IFDEF Pas64}
function HugeWordCompare_Original(const A, B: HugeWord): Integer;
var I, L, M : Integer;
F, G : Word32;
P, Q : PWord32;
T, U : PUInt64;
X, Y : UInt64;
begin
L := A.Used;
M := B.Used;
if L > M then
Result := 1 else
if L < M then
Result := -1
else
begin
P := A.Data;
Q := B.Data;
if P = Q then
begin
Result := 0;
exit;
end;
Inc(P, L);
Inc(Q, L);
T := Pointer(P);
U := Pointer(Q);
for I := (L div 2) - 1 downto 0 do
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
if X <> Y then
begin
if X < Y then
Result := -1
else
Result := 1;
exit;
end;
end;
if L mod 2 = 1 then
begin
P := A.Data;
Q := B.Data;
F := P^;
G := Q^;
if F <> G then
begin
if F < G then
Result := -1
else
Result := 1;
exit;
end;
end;
Result := 0;
end;
end;
function HugeWordCompare(const A, B: HugeWord): Integer;
var L, M : Integer;
F, G : Word32;
P, Q : PWord32;
T, U : PUInt64;
X, Y : UInt64;
begin
L := A.Used;
M := B.Used;
if L > M then
Result := 1 else
if L < M then
Result := -1
else
begin
P := A.Data;
Q := B.Data;
if P = Q then
begin
Result := 0;
exit;
end;
Inc(P, L);
Inc(Q, L);
T := Pointer(P);
U := Pointer(Q);
while L >= 8 do
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
if X = Y then
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
if X = Y then
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
if X = Y then
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
end;
end;
end;
if X <> Y then
begin
if X < Y then
Result := -1
else
Result := 1;
exit;
end;
Dec(L, 8);
end;
while L >= 2 do
begin
Dec(T);
Dec(U);
X := T^;
Y := U^;
if X <> Y then
begin
if X < Y then
Result := -1
else
Result := 1;
exit;
end;
Dec(L, 2);
end;
if L = 1 then
begin
P := A.Data;
Q := B.Data;
F := P^;
G := Q^;
if F <> G then
begin
if F < G then
Result := -1
else
Result := 1;
exit;
end;
end;
Result := 0;
end;
end;
{$ELSE}
function HugeWordCompare(const A, B: HugeWord): Integer;
var I, L, M : Integer;
F, G : Word32;
P, Q : PWord32;
begin
L := A.Used;
M := B.Used;
if L > M then
Result := 1 else
if L < M then
Result := -1
else
begin
P := A.Data;
Q := B.Data;
if P = Q then
begin
Result := 0;
exit;
end;
Inc(P, L);
Inc(Q, L);
for I := L - 1 downto 0 do
begin
Dec(P);
Dec(Q);
F := P^;
G := Q^;
if F <> G then
begin
if F < G then
Result := -1
else
Result := 1;
exit;
end;
end;
Result := 0;
end;
end;
{$ENDIF}
{ HugeWord Min/Max }
{ Post: A is minimum/maximum of A and B. }
procedure HugeWordMin(var A: HugeWord; const B: HugeWord);
begin
if HugeWordCompare(A, B) <= 0 then
exit;
HugeWordAssign(A, B);
end;
procedure HugeWordMax(var A: HugeWord; const B: HugeWord);
begin
if HugeWordCompare(A, B) >= 0 then
exit;
HugeWordAssign(A, B);
end;
function HugeWordGetBitCount(const A: HugeWord): Integer;
begin
Result := HugeWordGetSize(A) * HugeWordElementBits;
end;
{ HugeWord SetBits }
{ Sets the number of bits in the HugeWord. }
{ Pre: Bits must be multiple of 32. }
{ Post: A NOT normalised. }
procedure HugeWordSetBitCount(var A: HugeWord; const Bits: Integer);
begin
if Bits mod HugeWordElementBits <> 0 then
RaiseInvalidOpError;
HugeWordSetSize(A, Bits div HugeWordElementBits);
end;
{ HugeWord Bit State }
{ Pre: B is bit index (0 based) }
function HugeWordIsBitSet(const A: HugeWord; const B: Integer): Boolean;
var L : Integer;
P : PWord32;
begin
L := A.Used;
if (B < 0) or (B >= L * HugeWordElementBits) then
Result := False
else
begin
P := A.Data;
Inc(P, B shr 5);
Result := (P^ and Word32(1 shl (B and $1F)) <> 0);
end;
end;
{ Pre: B is in range }
function HugeWordIsBitSet_IR(const A: HugeWord; const B: Integer): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
var P : PWord32;
begin
P := A.Data;
Inc(P, B shr 5);
Result := (P^ and Word32(1 shl (B and $1F)) <> 0);
end;
procedure HugeWordSetBit(var A: HugeWord; const B: Integer);
var I, L : Integer;
P : PWord32;
begin
L := A.Used;
if B < 0 then
exit;
I := B shr 5;
if I >= L then
HugeWordSetSize(A, I + 1);
P := A.Data;
Inc(P, I);
P^ := P^ or Word32(1 shl (B and $1F));
end;
procedure HugeWordSetBit0(var A: HugeWord);
var P : PWord32;
begin
if A.Used > 0 then
begin
P := A.Data;
P^ := P^ or 1;
end
else
HugeWordAssignOne(A);
end;
procedure HugeWordClearBit(var A: HugeWord; const B: Integer);
var I, L : Integer;
P : PWord32;
begin
L := A.Used;
if (B < 0) or (B >= L * HugeWordElementBits) then
exit;
I := B shr 5;
P := A.Data;
Inc(P, I);
P^ := P^ and not Word32(1 shl (B and $1F));
end;
procedure HugeWordToggleBit(var A: HugeWord; const B: Integer);
var I, L : Integer;
P : PWord32;
begin
L := A.Used;
if B < 0 then
exit;
I := B shr 5;
if I >= L then
HugeWordSetSize(A, I + 1);
P := A.Data;
Inc(P, I);
P^ := P^ xor Word32(1 shl (B and $1F));
end;
{ HugeWord Bit Scan }
{ Post: Returns index of bit in A, or -1 if none found }
function HugeWordSetBitScanForward(const A: HugeWord): Integer;
var P : PWord32;
V : Word32;
I : Integer;
J : Byte;
begin
P := A.Data;
for I := 0 to A.Used - 1 do
begin
V := P^;
if V <> 0 then
for J := 0 to HugeWordElementBits - 1 do
if V and BitMaskTable32[J] <> 0 then
begin
Result := I * HugeWordElementBits + J;
exit;
end;
Inc(P);
end;
Result := -1;
end;
const
Word8SetBitScanReverseLookup: array[Byte] of Integer = (
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
);
function Word32SetBitScanReverse(const A: Word32): Integer; {$IFDEF UseInline}inline;{$ENDIF}
begin
if A and $FFFF0000 <> 0 then
if A and $FF000000 <> 0 then
Result := Word8SetBitScanReverseLookup[Byte(A shr 24)] + 24
else
Result := Word8SetBitScanReverseLookup[Byte(A shr 16)] + 16
else
if A and $0000FF00 <> 0 then
Result := Word8SetBitScanReverseLookup[Byte(A shr 8)] + 8
else
Result := Word8SetBitScanReverseLookup[Byte(A)];
end;
function HugeWordSetBitScanReverse(const A: HugeWord): Integer;
var P : PWord32;
L : Integer;
V : Word32;
I : Integer;
J : Byte;
begin
P := A.Data;
L := A.Used;
Inc(P, L - 1);
for I := L - 1 downto 0 do
begin
V := P^;
if V <> 0 then
begin
J := Word32SetBitScanReverse(V);
Result := I * HugeWordElementBits + J;
exit;
end;
Dec(P);
end;
Result := -1;
end;
function HugeWordClearBitScanForward(const A: HugeWord): Integer;
var P : PWord32;
V : Word32;
I : Integer;
J : Byte;
begin
if A.Used = 0 then
begin
Result := 0;
exit;
end;
P := A.Data;
for I := 0 to A.Used - 1 do
begin
V := P^;
if V <> $FFFFFFFF then
for J := 0 to HugeWordElementBits - 1 do
if V and BitMaskTable32[J] = 0 then
begin
Result := I * HugeWordElementBits + J;
exit;
end;
Inc(P);
end;
Result := A.Used * HugeWordElementBits;
end;
function HugeWordClearBitScanReverse(const A: HugeWord): Integer;
var B : Integer;
begin
if A.Used = 0 then
begin
Result := 0;
exit;
end;
B := HugeWordSetBitScanReverse(A);
if B < 0 then
Result := A.Used * HugeWordElementBits
else
Result := B + 1;
end;
{ HugeWord Bit Shift }
{ Post: A not normalised }
{ A's size expanded if required to accommodate result }
{ A's size may be reduced }
procedure HugeWordShl(var A: HugeWord; const B: Integer);
var E, I, L, N : Integer;
C, D : Byte;
P, Q, T : PWord32;
F : Word32;
begin
if B = 0 then
exit;
if B < 0 then
begin
HugeWordShr(A, -B);
exit;
end;
L := A.Used;
if L = 0 then
exit;
E := B div 32; // number of new full Word32s
D := B mod 32; // number of new remaining bits
N := E;
// check if high bits require additional Word32
// expand size of A if required
if D > 0 then
begin
P := A.Data;
Inc(P, L - 1);
F := P^ shr (32 - D);
if F <> 0 then
Inc(N);
if N > 0 then
HugeWordSetSize(A, L + N);
if F <> 0 then
begin
P := A.Data;
Inc(P, L + N - 1);
P^ := F;
end;
end else
if N > 0 then
HugeWordSetSize(A, L + N);
// shift A
C := 32 - D;
P := A.Data;
Inc(P, L + E - 1); // P = A[L + E - 1]
for I := L + E - 1 downto E + 1 do
begin
Q := A.Data;
Inc(Q, I - E); // Q = A[I - E]
T := Q;
Dec(T); // T = A[I - E - 1]
P^ := (Q^ shl D) or (T^ shr C);
Dec(P);
end;
P^ := PWord32(A.Data)^ shl D; // A[E] := A[0] shl D
Dec(P);
for I := E - 1 downto 0 do
begin
P^ := 0; // A[I] := 0
Dec(P);
end;
end;
{$IFDEF _Asm64}
procedure HugeWordShl1(var A: HugeWord); assembler;
asm
end;
{$ELSE}
{$IFDEF Pas64}
procedure HugeWordShl1_Pas64_Original(var A: HugeWord);
var I, L : Integer;
M : PWord32;
F : Word32;
P, Q : PUInt64;
V, W : UInt64;
begin
L := A.Used;
if L = 0 then
exit;
M := A.Data;
Inc(M, L - 1);
if M^ and $80000000 <> 0 then // A[L - 1] high bit set
begin
HugeWordSetSize_NoZeroMem(A, L + 1);
M := A.Data;
Inc(M, L);
M^ := 1; // A[L] := 1
Dec(M);
end;
if L = 1 then
begin
M^ := Word32(M^ shl 1);
exit;
end;
Dec(M);
P := Pointer(M);
W := P^;
Q := P;
Dec(Q);
for I := (L div 2) - 1 downto 1 do
begin
V := Q^;
// A[I] := (A[I] shl 1) or (A[I - 1] shr 63)
// P^ := (P^ shl 1) or (Q^ shr 63);
P^ := (W shl 1) or (V shr 63);
W := V;
Dec(P);
Dec(Q);
end;
// P^ := P^ shl 1; // A[0] := A[0] shl 1
W := W shl 1;
if L and 1 = 1 then
begin
M := Pointer(P);
Dec(M);
F := M^;
M^ := Word32(F shl 1);
W := W or (F shr 31);
end;
P^ := W;
end;
procedure HugeWordShl1(var A: HugeWord);
var N : Integer;
L : Integer;
P : PUInt64;
C : UInt64;
F : UInt64;
Q : PUInt32;
G : UInt32;
begin
N := A.Used;
if N = 0 then
exit;
P := A.Data;
C := 0;
L := N;
while L >= 8 do
begin
F := P^;
P^ := (F shl 1) or C;
Inc(P);
C := F shr 63;
F := P^;
P^ := (F shl 1) or C;
Inc(P);
C := F shr 63;
F := P^;
P^ := (F shl 1) or C;
Inc(P);
C := F shr 63;
F := P^;
P^ := (F shl 1) or C;
Inc(P);
C := F shr 63;
Dec(L, 8);
end;
while L >= 2 do
begin
F := P^;
P^ := (F shl 1) or C;
C := F shr 63;
Inc(P);
Dec(L, 2);
end;
if L = 1 then
begin
Q := Pointer(P);
G := Q^;
Q^ := (G shl 1) or C;
C := G shr 31;
end;
if C = 1 then
begin
HugeWordSetSize_NoZeroMem(A, N + 1);
Q := A.Data;
Inc(Q, N);
Q^ := 1;
end;
end;
{$ELSE}
procedure HugeWordShl1(var A: HugeWord);
var I, L : Integer;
P, Q : PWord32;
V, W : Word32;
begin
L := A.Used;
if L = 0 then
exit;
P := A.Data;
Inc(P, L - 1);
if P^ and $80000000 <> 0 then // A[L - 1] high bit set
begin
HugeWordSetSize(A, L + 1);
P := A.Data;
Inc(P, L);
P^ := 1; // A[L] := 1
Dec(P);
end;
W := P^;
Q := P;
Dec(Q);
V := Q^;
for I := L - 1 downto 1 do
begin
// A[I] := (A[I] shl 1) or (A[I - 1] shr 31)
// P^ := (P^ shl 1) or (Q^ shr 31);
P^ := (W shl 1) or (V shr 31);
W := V;
Dec(P);
Dec(Q);
V := Q^;
end;
// P^ := P^ shl 1; // A[0] := A[0] shl 1
P^ := W shl 1;
end;
{$ENDIF}
{$ENDIF}
procedure HugeWordShr(var A: HugeWord; const B: Integer);
var E, I, L : Integer;
C, D : Byte;
P, Q, T : PWord32;
F : Word32;
begin
if B = 0 then
exit;
if B < 0 then
begin
HugeWordShl(A, -B);
exit;
end;
L := A.Used;
if L = 0 then
exit;
if B >= L * 32 then
begin
HugeWordAssignZero(A);
exit;
end;
E := B div 32;
D := B mod 32;
C := 32 - D;
P := A.Data; // P = A[0]
Q := P;
Inc(Q, E); // Q = A[E]
T := Q;
Inc(T); // T = A[E + 1]
for I := 0 to L - E - 2 do
begin
// A[I] := (A[I + E] shr D) or (A[I + E + 1] shl C)
F := (Q^ shr D);
if C < 32 then // note: T^ shl 32 evaluates to T^ and not 0
F := F or (T^ shl C);
P^ := F;
Inc(P);
Inc(Q);
Inc(T);
end;
Q := A.Data;
Inc(Q, L - 1); // Q = A[L - 1]
P^ := Q^ shr D; // A[L - E - 1] := A[L - 1] shr D
for I := L - E to L - 1 do
begin
Inc(P);
P^ := 0; // A[I] := 0
end;
end;
procedure HugeWordShr1_Original(var A: HugeWord);
var I, L : Integer;
P, Q : PWord32;
V, W : Word32;
begin
L := A.Used;
if L = 0 then
exit;
P := A.Data; // P := A[0]
Q := P;
Inc(Q); // Q := A[1]
W := P^;
for I := 0 to L - 2 do
begin
// A[I] := (A[I] shr 1) or (A[I + 1] shl 31)
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
// ----
Inc(P);
Inc(Q);
end;
P^ := W shr 1; // A[L - 1] := A[L - 1] shr 1
end;
procedure HugeWordShr1(var A: HugeWord);
var L : Integer;
P, Q : PWord32;
V, W : Word32;
begin
L := A.Used;
if L = 0 then
exit;
P := A.Data; // P := A[0]
Q := P;
Inc(Q); // Q := A[1]
W := P^;
while L >= 5 do
begin
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
Inc(P);
Inc(Q);
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
Inc(P);
Inc(Q);
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
Inc(P);
Inc(Q);
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
Inc(P);
Inc(Q);
Dec(L, 4);
end;
while L >= 2 do
begin
V := W;
W := Q^;
P^ := (V shr 1) or (W shl 31);
Inc(P);
Inc(Q);
Dec(L);
end;
P^ := W shr 1; // A[L - 1] := A[L - 1] shr 1
end;
{ HugeWord Logical NOT }
{ Pre: Any A }
{ Post: A's length unchanged }
{ A not normalised }
procedure HugeWordNot(var A: HugeWord);
var I, L : Integer;
P : PWord32;
begin
L := A.Used;
if L = 0 then
exit;
P := A.Data;
for I := 0 to L - 1 do
begin
P^ := not P^;
Inc(P);
end;
end;
{ HugeWord Logical OR }
{ Pre: Any A and B }
{ Post: A as large as largest of A and B }
{ A normalised if A and B was normalised }
procedure HugeWordOrHugeWord(var A: HugeWord; const B: HugeWord);
var I, L, M, N : Integer;
P, Q : PWord32;
begin
L := A.Used;
if L = 0 then
begin
HugeWordAssign(A, B);
exit;
end;
M := B.Used;
if M = 0 then
exit;
if L > M then
N := L
else
N := M;
if L < N then
HugeWordSetSize(A, N);
P := A.Data;
Q := B.Data;
for I := 0 to M - 1 do
begin
P^ := P^ or Q^;
Inc(P);
Inc(Q);
end;
end;
{ HugeWord Logical AND }
{ Pre: Any A and B }
{ Post: A as large as smallest of A and B }
{ A not normalised. }
procedure HugeWordAndHugeWord(var A: HugeWord; const B: HugeWord);
var I, L, M, N : Integer;
P, Q : PWord32;
begin
L := A.Used;
if L = 0 then
exit;
M := B.Used;
if M = 0 then
begin
HugeWordAssignZero(A);
exit;
end;
if L < M then
N := L
else
N := M;
HugeWordSetSize(A, N);
P := A.Data;
Q := B.Data;
for I := 0 to M - 1 do
begin
P^ := P^ and Q^;
Inc(P);
Inc(Q);
end;
end;
{ HugeWord Logical XOR }
{ Pre: Any A and B }
{ Post: A as large as largest of A and B }
{ A not normalised. }
procedure HugeWordXorHugeWord(var A: HugeWord; const B: HugeWord);
var I, L, M, N : Integer;
P, Q : PWord32;
begin
L := A.Used;
if L = 0 then
begin
HugeWordAssign(A, B);
exit;
end;
M := B.Used;
if M = 0 then
exit;
if L > M then
N := L
else
N := M;
if L < N then
HugeWordSetSize(A, N);
P := A.Data;
Q := B.Data;
for I := 0 to M - 1 do
begin
P^ := P^ xor Q^;
Inc(P);
Inc(Q);
end;
end;
{ HugeWord Add Word }
{ Pre: A normalised }
{ Post: A contains result of A + B }
{ A normalised }
procedure HugeWordAddWord32(var A: HugeWord; const B: Word32);
var L, I : Integer;
R : Int64;
C : Word32;
P : PWord32;
begin
if B = 0 then
exit;
L := A.Used;
if L = 0 then
begin
HugeWordAssignWord32(A, B);
exit;
end;
P := A.Data;
C := B;
for I := 0 to L - 1 do
begin
R := C;
Inc(R, P^);
P^ := Int64Rec(R).Lo;
C := Int64Rec(R).Hi;
if C = 0 then
exit;
Inc(P);
end;
HugeWordSetSize(A, L + 1);
P := A.Data;
Inc(P, L);
P^ := C;
end;
{ HugeWord Add }
{ Pre: A and B normalised }
{ Post: A contains result of A + B }
{ A normalised }
procedure HugeWordAdd(var A: HugeWord; const B: HugeWord);
var L, M : Integer;
I : Integer;
R : UInt64;
P, Q : PWord32;
begin
M := B.Used;
if M = 0 then
exit;
L := A.Used;
if L = 0 then
begin
HugeWordAssign(A, B);
exit;
end;
if L < M then
begin
HugeWordSetSize(A, M);
L := M;
end;
P := A.Data;
Q := B.Data;
R := 0;
for I := 0 to M - 1 do
begin
Inc(R, P^);
Inc(R, Q^);
P^ := Word32(R); // Int64Rec(R).Lo
R := R shr 32; // Int64Rec(R).Hi
Inc(P);
Inc(Q);
end;
if R = 0 then
exit;
for I := M to L - 1 do
begin
Inc(R, P^);
P^ := Word32(R); // Int64Rec(R).Lo;
R := R shr 32; // Int64Rec(R).Hi;
if R = 0 then
exit;
Inc(P);
end;
HugeWordSetSize(A, L + 1);
P := A.Data;
Inc(P, L);
P^ := R;
end;
procedure HugeWordInc(var A: HugeWord);
begin
HugeWordAddWord32(A, 1);
end;
{ HugeWord Subtract Word }
{ Pre: A normalised }
{ Post: A contains result of A - B }
{ A normalised }
{ Result is sign of A (-1 or +1) or 0 if A is zero }
function HugeWordSubtractWord32(var A: HugeWord; const B: Word32): Integer;
var C : Integer;
L, I : Integer;
R : Int64;
P : PWord32;
begin
L := A.Used;
// Handle A = 0 or B = 0
if L = 0 then
begin
if B = 0 then
begin
Result := 0;
exit;
end;
HugeWordAssignWord32(A, B);
Result := -1;
exit;
end;
if B = 0 then
begin
Result := 1;
exit;
end;
// Handle A = B
C := HugeWordCompareWord32(A, B);
if C = 0 then
begin
HugeWordAssignZero(A);
Result := 0;
exit;
end;
// Handle A < B
if C < 0 then
begin
HugeWordAssignWord32(A, B - PWord32(A.Data)^);
Result := -1;
exit;
end;
// Handle A > B
// Subtract
P := A.Data;
for I := 0 to L - 1 do
begin
if I = 0 then
begin
R := $100000000;
Dec(R, B);
end
else
R := $FFFFFFFF;
Inc(R, P^);
P^ := Int64Rec(R).Lo;
if Int64Rec(R).Hi > 0 then
break;
Inc(P);
end;
// Normalise
HugeWordNormalise(A);
// Return sign
if HugeWordIsZero(A) then
Result := 0
else
Result := 1;
end;
{ HugeWord Subtract (A Larger) }
{ Pre: A and B normalised }
{ A is larger than B }
{ A is not zero, B is not zero }
{ Post: A contains result of A - B }
{ A normalised }
procedure HugeWordSubtract_ALarger(var A: HugeWord; const B: HugeWord);
var
L, M : Integer;
R : UInt64;
I : Integer;
P, Q : PWord32;
begin
Assert(A.Used > 0);
Assert(B.Used > 0);
Assert(A.Used >= B.Used);
// Subtract
P := A.Data;
Q := B.Data;
L := A.Used;
M := B.Used;
R := 1;
I := M;
while I >= 2 do
begin
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
P^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(Q);
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
P^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(Q);
Dec(I, 2);
end;
if I = 1 then
begin
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
P^ := Word32(R);
Inc(P);
R := R shr 32;
Dec(I);
end;
Assert(I = 0);
if R = 0 then // borrowed
begin
I := L - M;
while I > 0 do
begin
R := $FFFFFFFF;
Inc(R, P^);
P^ := Word32(R);
R := R shr 32;
if R > 0 then
break; // not borrowed
Inc(P);
Dec(I);
end;
end;
Assert(R = 1);
// Normalise (leading zeros)
HugeWordNormalise(A);
end;
{ HugeWord Subtract }
{ Pre: A and B normalised }
{ Post: A contains result of A - B }
{ A normalised }
{ Result is sign of A (-1 or +1) or 0 if A is zero }
function HugeWordSubtract(var A: HugeWord; const B: HugeWord): Integer;
var C : Integer;
D, E : PHugeWord;
L, M : Integer;
R : UInt64;
I : Integer;
P, Q, Z : PWord32;
begin
// Handle A = 0 or B = 0
if HugeWordIsZero(A) then
begin
if HugeWordIsZero(B) then
begin
Result := 0;
exit;
end;
HugeWordAssign(A, B);
Result := -1;
exit;
end;
if HugeWordIsZero(B) then
begin
Result := 1;
exit;
end;
// Handle A = B
C := HugeWordCompare(A, B);
if C = 0 then
begin
HugeWordAssignZero(A);
Result := 0;
exit;
end;
// Swap around if A < B
if C > 0 then
begin
D := @A;
E := @B;
end
else
begin
HugeWordSetSize(A, B.Used);
D := @B;
E := @A;
end;
// Subtract
P := D^.Data;
Q := E^.Data;
Z := A.Data;
L := D^.Used;
M := E^.Used;
R := 1;
I := M;
while I >= 2 do
begin
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
Z^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(Q);
Inc(Z);
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
Z^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(Q);
Inc(Z);
Dec(I, 2);
end;
if I = 1 then
begin
Inc(R, $FFFFFFFF);
Inc(R, P^);
Dec(R, Q^);
Z^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(Z);
end;
if R = 0 then // borrowed
begin
I := L - M;
while I > 0 do
begin
R := $FFFFFFFF;
Inc(R, P^);
Z^ := Word32(R);
R := R shr 32;
if R > 0 then
break; // not borrowed
Inc(P);
Inc(Z);
Dec(I);
end;
end;
Assert(R = 1);
// Normalise (leading zeros)
HugeWordNormalise(A);
// Return sign
if C > 0 then
Result := 1
else
Result := -1;
end;
procedure HugeWordDec(var A: HugeWord);
begin
{$IFOPT R+}
if HugeWordIsZero(A) then
RaiseRangeError;
{$ENDIF}
HugeWordSubtractWord32(A, 1);
end;
{ HugeWord Multiply Word }
{ Pre: A and B normalised }
{ Post: Result contains A * B }
{ Result NOT normalised. Result has size of Length(A) + Length(B) }
procedure HugeWordMultiplyWord8(var A: HugeWord; const B: Byte);
var I, L : Integer;
C : Int64;
P : PWord32;
begin
L := A.Used;
if L = 0 then
exit;
if B = 0 then
begin
HugeWordAssignZero(A);
exit;
end;
if B = 1 then
exit;
if B = 2 then
begin
HugeWordShl1(A);
exit;
end;
P := A.Data;
C := Int64(P^) * B;
P^ := Int64Rec(C).Lo;
for I := 1 to L - 1 do
begin
Inc(P);
C := C shr 32;
C := C + (Int64(P^) * B);
// P^ := Int64Rec(C).Lo;
P^ := Word32(C);
end;
C := C shr 32;
if C > 0 then
begin
HugeWordSetSize(A, L + 1);
P := A.Data;
Inc(P, L);
// P^ := Int64Rec(C).Lo;
P^ := Word32(C);
end;
end;
procedure HugeWordMultiplyWord16(var A: HugeWord; const B: Word);
var I, L : Integer;
C : Int64;
P : PWord32;
begin
L := A.Used;
if L = 0 then
exit;
if B = 0 then
begin
HugeWordAssignZero(A);
exit;
end;
if B = 1 then
exit;
P := A.Data;
C := Int64(P^) * B;
P^ := Int64Rec(C).Lo;
for I := 1 to L - 1 do
begin
Inc(P);
C := C shr 32;
C := C + (Int64(P^) * B);
// P^ := Int64Rec(C).Lo;
P^ := Word32(C);
end;
C := C shr 32;
if C > 0 then
begin
HugeWordSetSize(A, L + 1);
P := A.Data;
Inc(P, L);
// P^ := Int64Rec(C).Lo;
P^ := Word32(C);
end;
end;
procedure HugeWordMultiplyWord32(var A: HugeWord; const B: Word32);
var F : HugeWord;
begin
HugeWordInitWord32(F, B);
HugeWordMultiply(A, A, F);
HugeWordFinalise(F);
end;
{$IFDEF ASM386_DELPHI}
type
Word64 = Int64;
procedure Word32MultiplyWord32(const A, B: Word32; var R: Word64);
asm
// EAX = A, EDX = B, [ECX] = R
mul edx
mov [ecx], eax
mov [ecx + 4], edx
end;
{$ENDIF}
{ HugeWord Long Multiplication }
{ Multiply using the 'long multiplication' method. Time is o(n^2). }
{ Pre: Res initialised, A and B normalised }
{ Res is not the same instance as A or B }
{ Post: Res contains A * B }
{ Res NOT normalised. Res has size of Size(A) + Size(B) }
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
procedure HugeWordMultiply_Long_NN_Unsafe(var Res: HugeWord; const A, B: HugeWord);
var L, M : Integer;
I, J : Integer;
R : Word64;
{$IFDEF ASM386_DELPHI}
TM : Int64;
V : Word32;
{$ELSE}
V : UInt64;
{$ENDIF}
P, Q : PWord32;
F : PWord32;
ADat : PWord32;
RDat : PWord32;
begin
Assert(Res.Data <> A.Data);
Assert(Res.Data <> B.Data);
// handle zero
L := A.Used;
M := B.Used;
if (L = 0) or (M = 0) then
begin
HugeWordAssignZero(Res);
exit;
end;
// handle one and two
if (L = 1) or (M = 1) then
begin
if L = 1 then
if HugeWordIsOne(A) then
begin
HugeWordAssign(Res, B);
exit;
end;
if M = 1 then
if HugeWordIsOne(B) then
begin
HugeWordAssign(Res, A);
exit;
end;
if L = 1 then
if HugeWordIsTwo(A) then
begin
HugeWordAssign(Res, B);
HugeWordShl1(Res);
exit;
end;
if M = 1 then
if HugeWordIsTwo(B) then
begin
HugeWordAssign(Res, A);
HugeWordShl1(Res);
exit;
end;
end;
// multiply
HugeWordAssignZero(Res);
HugeWordSetSize(Res, L + M);
ADat := A.Data;
Q := B.Data;
RDat := Res.Data;
for I := 0 to M - 1 do
begin
V := Q^;
R := 0;
P := ADat;
F := RDat;
Inc(F, I);
J := L;
while J > 0 do
begin
Inc(R, F^);
{$IFDEF FREEPASCAL}
R := R + (V * P^);
{$ELSE}
{$IFDEF ASM386_DELPHI}
Word32MultiplyWord32(Word32(V), P^, TM);
Inc(R, TM);
{$ELSE}
{$IFDEF CPU_X86_64}
R := R + V * P^;
{$ELSE}
Inc(R, V * P^);
{$ENDIF}
{$ENDIF}
{$ENDIF}
F^ := Word32(R);
R := R shr 32;
Inc(P);
Inc(F);
Dec(J);
end;
F^ := Word32(R);
Inc(Q);
end;
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
procedure HugeWordMultiply_Long_NN_Safe(var Res: HugeWord; const A, B: HugeWord);
var T : HugeWord;
begin
HugeWordInit(T);
try
HugeWordMultiply_Long_NN_Unsafe(T, A, B);
HugeWordAssign(Res, T);
finally
HugeWordFinalise(T);
end;
end;
procedure HugeWordMultiply_Long_NN(var Res: HugeWord; const A, B: HugeWord);
begin
if (Res.Data = A.Data) or (Res.Data = B.Data) then
HugeWordMultiply_Long_NN_Safe(Res, A, B)
else
HugeWordMultiply_Long_NN_Unsafe(Res, A, B);
end;
procedure HugeWordMultiply_Long(var Res: HugeWord; const A, B: HugeWord);
begin
HugeWordMultiply_Long_NN(Res, A, B);
HugeWordNormalise(Res);
end;
{ HugeWord Shift-Add Multiplication }
{ Multiply using the 'shift-add' method: }
{ + Set the Result to 0 }
{ + For each bit of the Multiplier (from right to left) do }
{ + If the bit is 1 then add the Multiplicand to the Result }
{ + Shift the Multiplicand left one bit }
{ Pre: Res initialised, A and B normalised }
{ Res may be same instance as A or B }
{ Post: Res contains A * B }
{ Res normalised. }
procedure HugeWordMultiply_ShiftAdd_Unsafe(var Res: HugeWord; const A, B: HugeWord);
var L, M, C, I : Integer;
D : HugeWord;
AP : PWord32;
AD : Word32;
AB : Word32;
begin
// handle zero
L := A.Used;
M := B.Used;
if (L = 0) or (M = 0) then
begin
HugeWordAssignZero(Res);
exit;
end;
// handle one and two
if (L = 1) or (M = 1) then
begin
if L = 1 then
if HugeWordIsOne(A) then
begin
HugeWordAssign(Res, B);
exit;
end;
if M = 1 then
if HugeWordIsOne(B) then
begin
HugeWordAssign(Res, A);
exit;
end;
if L = 1 then
if HugeWordIsTwo(A) then
begin
HugeWordAssign(Res, B);
HugeWordShl1(Res);
exit;
end;
if M = 1 then
if HugeWordIsTwo(B) then
begin
HugeWordAssign(Res, A);
HugeWordShl1(Res);
exit;
end;
end;
// multiply
HugeWordAssignZero(Res);
HugeWordInitHugeWord(D, B);
try
C := HugeWordSetBitScanReverse(A);
AP := A.Data;
AD := 0;
AB := $80000000;
for I := 0 to C do
begin
if AB = $80000000 then
begin
AD := AP^;
Inc(AP);
AB := 1;
end
else
AB := AB shl 1;
if AD and AB <> 0 then //if HugeWordIsBitSet_IR(A, I) then
HugeWordAdd(Res, D);
HugeWordShl1(D);
end;
finally
HugeWordFinalise(D);
end;
end;
procedure HugeWordMultiply_ShiftAdd_Safe(var Res: HugeWord; const A, B: HugeWord);
var R : HugeWord;
begin
HugeWordInitZero(R);
try
HugeWordMultiply_ShiftAdd_Unsafe(R, A, B);
HugeWordAssign(Res, R);
finally
HugeWordFinalise(R);
end;
end;
procedure HugeWordMultiply_ShiftAdd(var Res: HugeWord; const A, B: HugeWord);
begin
if (Res.Data = A.Data) or (Res.Data = B.Data) then
HugeWordMultiply_ShiftAdd_Safe(Res, A, B)
else
HugeWordMultiply_ShiftAdd_Unsafe(Res, A, B);
end;
(*
procedure karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
return num1*num2
/* calculates the size of the numbers */
m = min(size_base10(num1), size_base10(num2))
m2 = floor(m/2)
/*m2 = ceil(m/2) will also work */
/* split the digit sequences in the middle */
high1, low1 = split_at(num1, m2)
high2, low2 = split_at(num2, m2)
/* 3 calls made to numbers approximately half the size */
z0 = karatsuba(low1, low2)
z1 = karatsuba((low1 + high1), (low2 + high2))
z2 = karatsuba(high1, high2)
return (z2 * 10 ^ (m2 * 2)) + ((z1 - z2 - z0) * 10 ^ m2) + z0
*)
procedure HugeWordMultiply_Karatsuba(var Res: HugeWord; const A, B: HugeWord);
var
M, M2 : Integer;
Hi1, Lo1 : HugeWord;
Hi2, Lo2 : HugeWord;
P : PWord32;
Z0, Z1, Z2 : HugeWord;
R1, R2 : HugeWord;
begin
if (A.Used <= 4) or (B.Used <= 4) then
begin
HugeWordMultiply_Long(Res, A, B);
exit;
end;
if B.Used > A.Used then
M := B.Used
else
M := A.Used;
M2 := M div 2;
HugeWordInit(Hi1);
HugeWordInit(Lo1);
HugeWordSetSize(Hi1, A.Used - M2);
HugeWordSetSize(Lo1, M2);
P := A.Data;
Move(P^, Lo1.Data^, Lo1.Used * 4);
Inc(P, Lo1.Used);
Move(P^, Hi1.Data^, Hi1.Used * 4);
HugeWordInit(Hi2);
HugeWordInit(Lo2);
HugeWordSetSize(Hi2, B.Used - M2);
HugeWordSetSize(Lo2, M2);
P := B.Data;
Move(P^, Lo2.Data^, Lo2.Used * 4);
Inc(P, Lo2.Used);
Move(P^, Hi2.Data^, Hi2.Used * 4);
HugeWordInit(Z0);
HugeWordInit(Z1);
HugeWordInit(Z2);
// z0 = karatsuba(low1, low2)
HugeWordMultiply_Karatsuba(Z0, Lo1, Lo2);
// z2 = karatsuba(high1, high2)
HugeWordMultiply_Karatsuba(Z2, Hi1, Hi2);
// z1 = karatsuba((low1 + high1), (low2 + high2))
HugeWordAdd(Lo1, Hi1);
HugeWordAdd(Lo2, Hi2);
HugeWordMultiply_Karatsuba(Z1, Lo1, Lo2);
// return (z2 * 10 ^ (m2 * 2)) + ((z1 - z2 - z0) * 10 ^ m2) + z0
HugeWordInit(R1);
HugeWordSetSize(R1, Z2.Used + M2 * 2);
P := R1.Data;
Inc(P, M2 * 2);
Move(Z2.Data^, P^, Z2.Used * 4);
FillChar(R1.Data^, M2 * 2 * 4, 0);
HugeWordNormalise(R1);
HugeWordInit(R2);
HugeWordSetSize(R2, Z1.Used + M2);
P := R2.Data;
Inc(P, M2);
Move(Z1.Data^, P^, Z1.Used * 4);
FillChar(R2.Data^, M2 * 4, 0);
HugeWordNormalise(R2);
HugeWordAdd(R1, R2);
HugeWordSetSize(R2, Z2.Used + M2);
P := R2.Data;
Inc(P, M2);
Move(Z2.Data^, P^, Z2.Used * 4);
FillChar(R2.Data^, M2 * 4, 0);
HugeWordNormalise(R2);
HugeWordSubtract(R1, R2);
HugeWordSetSize(R2, Z0.Used + M2);
P := R2.Data;
Inc(P, M2);
Move(Z0.Data^, P^, Z0.Used * 4);
FillChar(R2.Data^, M2 * 4, 0);
HugeWordNormalise(R2);
HugeWordSubtract(R1, R2);
HugeWordAdd(R1, Z0);
HugeWordAssign(Res, R1);
HugeWordFinalise(R2);
HugeWordFinalise(R1);
HugeWordFinalise(Z2);
HugeWordFinalise(Z1);
HugeWordFinalise(Z0);
HugeWordFinalise(Lo2);
HugeWordFinalise(Hi2);
HugeWordFinalise(Lo1);
HugeWordFinalise(Hi1);
end;
{ HugeWord Multiplication }
{ Pre: A, B normalised }
{ Res initialised }
{ Post: Res contains A * B }
{ Res normalised }
{.DEFINE HugeInt_AlwaysMultiplyLong}
{.DEFINE HugeInt_AlwaysMultiplyShiftAdd}
procedure HugeWordMultiply(var Res: HugeWord; const A, B: HugeWord);
begin
{$IFDEF HugeInt_AlwaysMultiplyLong}
HugeWordMultiply_Long(Res, A, B);
{$ELSE}{$IFDEF HugeInt_AlwaysMultiplyShiftAdd}
HugeWordMultiply_ShiftAdd(Res, A, B);
{$ELSE}
HugeWordMultiply_Long(Res, A, B);
{$ENDIF}{$ENDIF}
end;
{ HugeWord Sqr }
{ Pre: Res initialised, A normalised }
{ Post: Res contains A * A }
{ Res normalised }
procedure HugeWordSqr(var Res: HugeWord; const A: HugeWord);
begin
HugeWordMultiply(Res, A, A);
end;
{ HugeWord Divide }
procedure HugeWordDivideWord32(const A: HugeWord; const B: Word32; var Q: HugeWord; out R: Word32);
var C, T : HugeWord;
begin
HugeWordInitWord32(C, B);
HugeWordInit(T);
try
HugeWordDivide(A, C, Q, T);
R := HugeWordToWord32(T);
finally
HugeWordFinalise(T);
HugeWordFinalise(C);
end;
end;
{ }
{ HugeWord Divide }
{ }
{ Divide using the "restoring radix two division" method. }
{ }
{ R := N }
{ D := D << n -- R and D need twice the word width of N and Q }
{ for i := n - 1 .. 0 do -- For example 31..0 for 32 bits }
{ R := 2 * R - D -- Trial subtraction from shifted value (multiplication by 2 is a shift in binary representation) }
{ if R >= 0 then }
{ q(i) := 1 -- Result-bit 1 }
{ else }
{ q(i) := 0 -- Result-bit 0 }
{ R := R + D -- New partial remainder is (restored) shifted value }
{ end }
{ end }
{ }
{ Where: N = Numerator, D = Denominator, n = #bits, }
{ R = Partial remainder, q(i) = bit #i of quotient }
{ }
procedure HugeWordDivide_RR_Unsafe_Orig(const A, B: HugeWord; var Q, R: HugeWord);
var C, F, D : Integer;
begin
// Handle special cases
if HugeWordIsZero(B) then // B = 0
RaiseDivByZeroError else
if HugeWordIsOne(B) then // B = 1
begin
HugeWordAssign(Q, A); // Q = A
HugeWordAssignZero(R); // R = 0
exit;
end;
if HugeWordIsZero(A) then // A = 0
begin
HugeWordAssignZero(Q); // Q = 0
HugeWordAssignZero(R); // R = 0
exit;
end;
C := HugeWordCompare(A, B);
if C < 0 then // A < B
begin
HugeWordAssign(R, A); // R = A
HugeWordAssignZero(Q); // Q = 0
exit;
end else
if C = 0 then // A = B
begin
HugeWordAssignOne(Q); // Q = 1
HugeWordAssignZero(R); // R = 0
exit;
end;
// Divide using "restoring radix two division"
HugeWordAssignZero(R); // R = remainder
HugeWordAssignZero(Q); // Q = quotient
F := HugeWordSetBitScanReverse(A); // F = high bit index in dividend
for C := 0 to F do
begin
// Shift high bit of dividend A into low bit of remainder R
HugeWordShl1(R);
if HugeWordIsBitSet_IR(A, F - C) then
HugeWordSetBit0(R);
// Shift quotient
HugeWordShl1(Q);
// Subtract divisor from remainder if large enough
D := HugeWordCompare(R, B);
if D >= 0 then
begin
if D = 0 then
HugeWordAssignZero(R)
else
HugeWordSubtract_ALarger(R, B);
// Set result bit in quotient
HugeWordSetBit0(Q);
end;
end;
end;
procedure HugeWordDivide_RR_Unsafe(const A, B: HugeWord; var Q, R: HugeWord);
var C, F, D, G, I : Integer;
begin
// Handle special cases
if HugeWordIsZero(B) then // B = 0
RaiseDivByZeroError else
if HugeWordIsOne(B) then // B = 1
begin
HugeWordAssign(Q, A); // Q = A
HugeWordAssignZero(R); // R = 0
exit;
end;
if HugeWordIsZero(A) then // A = 0
begin
HugeWordAssignZero(Q); // Q = 0
HugeWordAssignZero(R); // R = 0
exit;
end;
C := HugeWordCompare(A, B);
if C < 0 then // A < B
begin
HugeWordAssign(R, A); // R = A
HugeWordAssignZero(Q); // Q = 0
exit;
end else
if C = 0 then // A = B
begin
HugeWordAssignOne(Q); // Q = 1
HugeWordAssignZero(R); // R = 0
exit;
end;
// Divide using "restoring radix two division"
HugeWordAssignZero(R); // R = remainder
HugeWordAssignZero(Q); // Q = quotient
F := HugeWordSetBitScanReverse(A); // F = high bit index in dividend
G := HugeWordSetBitScanReverse(B); // G = high bit index in divisor
C := 0;
// First iteration over G + 1 bits
Assert(G > 0);
Assert(G <= F);
HugeWordSetSize(R, (G + 1 + 31) div 32);
for I := 0 to G do
if HugeWordIsBitSet_IR(A, F - I) then
HugeWordSetBit(R, G - I);
Inc(C, G + 1);
D := HugeWordCompare(R, B);
if D >= 0 then
begin
if D = 0 then
HugeWordAssignZero(R)
else
HugeWordSubtract_ALarger(R, B);
HugeWordSetBit0(Q);
end;
// Remaining iterations one bit at a time
while C <= F do
begin
// Shift high bit of dividend D into low bit of remainder R
HugeWordShl1(R);
if HugeWordIsBitSet_IR(A, F - C) then
HugeWordSetBit0(R);
// Shift quotient
HugeWordShl1(Q);
// Subtract divisor from remainder if large enough
D := HugeWordCompare(R, B);
if D >= 0 then
begin
if D = 0 then
HugeWordAssignZero(R)
else
HugeWordSubtract_ALarger(R, B);
// Set result bit in quotient
HugeWordSetBit0(Q);
end;
Inc(C);
end;
end;
procedure HugeWordDivide_RR_Safe(const A, B: HugeWord; var Q, R: HugeWord);
var D, E : HugeWord;
begin
HugeWordInit(D);
HugeWordInit(E);
try
HugeWordDivide_RR_Unsafe_Orig(A, B, D, E);
HugeWordAssign(Q, D);
HugeWordAssign(R, E);
finally
HugeWordFinalise(E);
HugeWordFinalise(D);
end;
end;
{ HugeWord Divide }
{ Pre: Q, R initialised, A, B normalised }
{ Post: Q is Quotient }
{ R is Remainder }
{ Q and R normalised }
procedure HugeWordDivide(const A, B: HugeWord; var Q, R: HugeWord);
begin
if (A.Data = Q.Data) or (A.Data = R.Data) or
(B.Data = Q.Data) or (B.Data = R.Data) then
HugeWordDivide_RR_Safe(A, B, Q, R)
else
HugeWordDivide_RR_Unsafe_Orig(A, B, Q, R);
end;
{ HugeWord Mod }
{ Pre: A and B normalised, R initialised }
{ Length(A) >= Length(B) }
{ Post: R is Remainder when A is divided by B }
{ R normalised }
procedure HugeWordMod_Orig(const A, B: HugeWord; var R: HugeWord);
var Q : HugeWord;
begin
HugeWordInit(Q);
try
HugeWordDivide(A, B, Q, R);
finally
HugeWordFinalise(Q);
end;
end;
procedure HugeWordMod_Alt(const A, B: HugeWord; var R: HugeWord);
var
Y, Z : HugeWord;
YP, ZP, TP : PHugeWord;
C : Integer;
begin
if HugeWordIsZero(B) then // B = 0
RaiseDivByZeroError;
HugeWordAssign(R, A);
if HugeWordCompare(R, B) > 0 then
begin
HugeWordInitHugeWord(Y, B);
HugeWordInitHugeWord(Z, B);
YP := @Y;
ZP := @Z;
repeat
TP := YP;
YP := ZP;
ZP := TP;
HugeWordAdd(ZP^, YP^);
until HugeWordCompare(R, ZP^) <= 0;
repeat
if not HugeWordIsZero(YP^) then
begin
C := HugeWordCompare(R, YP^);
if C > 0 then
HugeWordSubtract_ALarger(R, YP^)
else
if C = 0 then
HugeWordAssignZero(R);
end;
TP := YP;
YP := ZP;
ZP := TP;
HugeWordSubtract(YP^, ZP^);
until HugeWordCompare(YP^, ZP^) > 0;
HugeWordFinalise(Z);
HugeWordFinalise(Y);
end;
end;
procedure HugeWordMod_Unsafe_Orig(const A, B: HugeWord; var R: HugeWord);
var
I : integer;
BI : integer;
C : Integer;
begin
if HugeWordIsZero(B) then // B = 0
RaiseDivByZeroError;
if HugeWordIsOne(B) then // B = 1
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
if HugeWordIsZero(A) then // A = 0
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
C := HugeWordCompare(A, B);
if C < 0 then // A < B
begin
HugeWordAssign(R, A); // R = A
exit;
end else
if C = 0 then // A = B
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
HugeWordAssignZero(R);
BI := HugeWordSetBitScanReverse(A);
for I := BI downto 0 do
begin
HugeWordShl1(R);
if HugeWordIsBitSet_IR(A, I) then
HugeWordSetBit0(R);
C := HugeWordCompare(R, B);
if C > 0 then
HugeWordSubtract_ALarger(R, B)
else
if C = 0 then
HugeWordAssignZero(R);
end;
end;
procedure HugeWordMod_Unsafe(const A, B: HugeWord; var R: HugeWord);
var
I, J : Integer;
AI, BI : Integer;
C : Integer;
begin
if HugeWordIsZero(B) then // B = 0
RaiseDivByZeroError;
if HugeWordIsOne(B) then // B = 1
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
if HugeWordIsZero(A) then // A = 0
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
C := HugeWordCompare(A, B);
if C < 0 then // A < B
begin
HugeWordAssign(R, A); // R = A
exit;
end else
if C = 0 then // A = B
begin
HugeWordAssignZero(R); // R = 0
exit;
end;
HugeWordAssignZero(R);
AI := HugeWordSetBitScanReverse(A);
BI := HugeWordSetBitScanReverse(B);
// First iteration over BI + 1 bits
Assert(BI > 0);
Assert(BI <= AI);
HugeWordSetSize(R, (BI + 1 + 31) div 32);
for J := 0 to BI do
if HugeWordIsBitSet_IR(A, AI - J) then
HugeWordSetBit(R, BI - J);
C := HugeWordCompare(R, B);
if C > 0 then
HugeWordSubtract_ALarger(R, B)
else
if C = 0 then
HugeWordAssignZero(R);
I := AI;
Dec(I, BI + 1);
// Remaining iterations one bit at a time
while I >= 0 do
begin
HugeWordShl1(R);
if HugeWordIsBitSet_IR(A, I) then
HugeWordSetBit0(R);
C := HugeWordCompare(R, B);
if C > 0 then
HugeWordSubtract_ALarger(R, B)
else
if C = 0 then
HugeWordAssignZero(R);
Dec(I);
end;
end;
procedure HugeWordMod(const A, B: HugeWord; var R: HugeWord);
var
T : HugeWord;
begin
if (A.Data = R.Data) or (B.Data = R.Data) then
begin
HugeWordInit(T);
HugeWordMod_Unsafe(A, B, T);
HugeWordAssign(R, T);
HugeWordFinalise(T);
end
else
HugeWordMod_Unsafe(A, B, R);
end;
{ HugeWord GCD }
{ Post: R contains GCD(A, B) }
{ Uses the Euclidean algorithm }
procedure HugeWordGCD(const A, B: HugeWord; var R: HugeWord);
var C, D, T : HugeWord;
begin
HugeWordInitHugeWord(C, A);
HugeWordInitHugeWord(D, B);
HugeWordInit(T);
try
while not HugeWordIsZero(D) do
begin
HugeWordAssign(T, D);
HugeWordMod(C, D, D);
HugeWordAssign(C, T);
end;
HugeWordAssign(R, C);
finally
HugeWordFinalise(T);
HugeWordFinalise(D);
HugeWordFinalise(C);
end;
end;
{ HugeWord Power operation }
{ Calculates A^B }
{ Pre: A initialised }
procedure HugeWordPower(var A: HugeWord; const B: Word32);
var R, C : HugeWord;
D : Word32;
begin
if B = 0 then
begin
HugeWordAssignOne(A);
exit;
end;
if HugeWordIsZero(A) or HugeWordIsOne(A) then
exit;
if B = 1 then
exit;
if B = 2 then
begin
HugeWordSqr(A, A);
exit;
end;
HugeWordInitHugeWord(C, A);
HugeWordInitOne(R);
try
D := B;
while D > 0 do
if D and 1 = 0 then
begin
HugeWordSqr(C, C);
D := D shr 1;
end
else
begin
HugeWordMultiply(R, R, C);
Dec(D);
end;
HugeWordAssign(A, R);
finally
HugeWordFinalise(R);
HugeWordFinalise(C);
end;
end;
{ HugeWord PowerAndMod }
{ Calculates A^E mod M (Modular exponentiation) }
{ Pseudocode: }
{ Mod-Exp (a, e, m) }
{ product = 1 }
{ y = a }
{ while e > 0 do }
{ if e is odd then }
{ product = (product * y) % m; }
{ endif }
{ y = (y * y) % m; }
{ e = e / 2 }
{ end while }
{ return product }
{ Pre: Res initialised }
procedure HugeWordPowerAndMod(var Res: HugeWord; const A, E, M: HugeWord);
var P, T, Y, F{, Q} : HugeWord;
begin
HugeWordInitOne(P); // P = 1
HugeWordInit(T);
HugeWordInitHugeWord(Y, A); // Y = A
HugeWordInitHugeWord(F, E); // F = E
//HugeWordInit(Q);
try
while not HugeWordIsZero(F) do
begin
if HugeWordIsOdd(F) then
begin
HugeWordMultiply_Long_NN_Unsafe(T, P, Y); // T = P * Y HugeWordMultiply(T, P, Y)
HugeWordNormalise(T);
HugeWordMod_Unsafe(T, M, P);
//HugeWordDivide_RR_Unsafe(T, M, Q, P); // P = (P * Y) mod M
end;
HugeWordMultiply_Long_NN_Unsafe(T, Y, Y); // T = Y * Y HugeWordSqr(T, Y)
HugeWordNormalise(T);
HugeWordMod_Unsafe(T, M, Y);
//HugeWordDivide_RR_Unsafe(T, M, Q, Y); // Y = (Y * Y) mod M
HugeWordShr1(F); // F = F / 2
HugeWordNormalise(F);
end;
HugeWordAssign(Res, P);
finally
//HugeWordFinalise(Q);
HugeWordFinalise(F);
HugeWordFinalise(Y);
HugeWordFinalise(T);
HugeWordFinalise(P);
end;
end;
{ HugeWord String conversion }
function HugeWordToStrB(const A: HugeWord): UTF8String;
var B, C : HugeWord;
D : Word32;
S : RawByteString;
I, L : Integer;
begin
if HugeWordIsZero(A) then
begin
Result := '0';
exit;
end;
HugeWordInitHugeWord(B, A);
HugeWordInit(C);
try
S := '';
repeat
HugeWordDivideWord32(B, 10, C, D);
S := S + AnsiChar(Byte(D) + Ord('0'));
HugeWordAssign(B, C);
until HugeWordIsZero(B);
finally
HugeWordFinalise(C);
HugeWordFinalise(B);
end;
L := Length(S);
SetLength(Result, L);
for I := 1 to L do
Result[I] := S[L - I + 1];
end;
function HugeWordToStrU(const A: HugeWord): UnicodeString;
var B, C : HugeWord;
D : Word32;
S : UnicodeString;
I, L : Integer;
begin
if HugeWordIsZero(A) then
begin
Result := '0';
exit;
end;
HugeWordInitHugeWord(B, A);
HugeWordInit(C);
try
S := '';
repeat
HugeWordDivideWord32(B, 10, C, D);
S := S + WideChar(Byte(D) + Ord('0'));
HugeWordAssign(B, C);
until HugeWordIsZero(B);
finally
HugeWordFinalise(C);
HugeWordFinalise(B);
end;
L := Length(S);
SetLength(Result, L);
for I := 1 to L do
Result[I] := S[L - I + 1];
end;
function HugeWordToStr(const A: HugeWord): String;
begin
{$IFDEF StringIsUnicode}
Result := HugeWordToStrU(A);
{$ELSE}
Result := HugeWordToStrB(A);
{$ENDIF}
end;
{ HugeWord String conversion }
procedure StrToHugeWordB(const A: RawByteString; var R: HugeWord);
var I : Integer;
B : AnsiChar;
C : Word32;
begin
if A = '' then
RaiseConvertError;
HugeWordAssignZero(R);
for I := 1 to Length(A) do
begin
B := A[I];
if not (B in ['0'..'9']) then
RaiseConvertError;
C := Ord(A[I]) - Ord('0');
HugeWordMultiplyWord8(R, 10);
HugeWordAddWord32(R, C);
end;
end;
procedure StrToHugeWordU(const A: UnicodeString; var R: HugeWord);
var I : Integer;
B : WideChar;
C : Word32;
begin
if A = '' then
RaiseConvertError;
HugeWordAssignZero(R);
for I := 1 to Length(A) do
begin
B := A[I];
if (B < '0') or (B > '9') then
RaiseConvertError;
C := Ord(A[I]) - Ord('0');
HugeWordMultiplyWord8(R, 10);
HugeWordAddWord32(R, C);
end;
end;
procedure StrToHugeWord(const A: String; var R: HugeWord);
begin
{$IFDEF StringIsUnicode}
StrToHugeWordU(A, R);
{$ELSE}
StrToHugeWordB(A, R);
{$ENDIF}
end;
{ HugeWord Hex conversion }
const
HexLookupU = '0123456789ABCDEF';
HexLookupL = '0123456789abcdef';
HexLookupU_ByteStr : UTF8String = HexLookupU;
HexLookupL_ByteStr : UTF8String = HexLookupL;
HexLookupU_Str : String = HexLookupU;
HexLookupL_Str : String = HexLookupL;
function HugeWordToHexB(const A: HugeWord; const LowCase: Boolean): UTF8String;
var L, I, J : Integer;
P : PWord32;
F : Word32;
begin
if HugeWordIsZero(A) then
begin
Result := '00000000';
exit;
end;
L := A.Used;
SetLength(Result, L * 8);
P := A.Data;
Inc(P, L - 1);
for I := 0 to L - 1 do
begin
F := P^;
for J := 0 to 7 do
begin
if LowCase then
Result[I * 8 + J + 1] := AnsiChar(HexLookupL[(F shr 28) + 1])
else
Result[I * 8 + J + 1] := AnsiChar(HexLookupU[(F shr 28) + 1]);
F := F shl 4;
end;
Dec(P);
end;
end;
function HugeWordToHex(const A: HugeWord; const LowCase: Boolean): String;
var L, I, J : Integer;
P : PWord32;
F : Word32;
begin
if HugeWordIsZero(A) then
begin
Result := '00000000';
exit;
end;
L := A.Used;
SetLength(Result, L * 8);
P := A.Data;
Inc(P, L - 1);
for I := 0 to L - 1 do
begin
F := P^;
for J := 0 to 7 do
begin
if LowCase then
Result[I * 8 + J + 1] := Char(HexLookupL[(F shr 28) + 1])
else
Result[I * 8 + J + 1] := Char(HexLookupU[(F shr 28) + 1]);
F := F shl 4;
end;
Dec(P);
end;
end;
procedure HexToHugeWordB(const A: RawByteString; var R: HugeWord);
var L, N, C, I, J, K : Integer;
B : AnsiChar;
D, E : Byte;
F : Word32;
begin
L := Length(A);
if L = 0 then
RaiseConvertError;
// L = number of characters in strings
N := (L div 2) + (L mod 2);
// N = number of bytes
C := (N + 3) div 4;
// C = number of Word32s
HugeWordSetSize(R, C);
for I := 0 to C - 1 do
begin
F := 0;
for J := 0 to 7 do
begin
K := L - I * 8 - J;
if K < 1 then
B := '0'
else
B := A[L - I * 8 - J];
E := 16;
for D := 1 to 16 do
if (B = HexLookupU_ByteStr[D]) or
(B = HexLookupL_ByteStr[D]) then
begin
E := D - 1;
break;
end;
if E = 16 then
RaiseConvertError;
F := F or (E shl (J * 4));
end;
HugeWordSetElement(R, I, F);
end;
end;
procedure HexToHugeWord(const A: String; var R: HugeWord);
var L, N, C, I, J, K : Integer;
B : Char;
D, E : Byte;
F : Word32;
begin
L := Length(A);
if L = 0 then
RaiseConvertError;
// L = number of characters in strings
N := (L div 2) + (L mod 2);
// N = number of bytes
C := (N + 3) div 4;
// C = number of Word32s
HugeWordSetSize(R, C);
for I := 0 to C - 1 do
begin
F := 0;
for J := 0 to 7 do
begin
K := L - I * 8 - J;
if K < 1 then
B := '0'
else
B := A[L - I * 8 - J];
E := 16;
for D := 1 to 16 do
if (B = HexLookupU_Str[D]) or
(B = HexLookupL_Str[D]) then
begin
E := D - 1;
break;
end;
if E = 16 then
RaiseConvertError;
F := F or (E shl (J * 4));
end;
HugeWordSetElement(R, I, F);
end;
end;
{ HugeWord ISqrt }
{ Calculates integer square root of A using Newton's method. }
{ Pre: A normalised }
{ Post: A normalised }
procedure HugeWordISqrt(var A: HugeWord);
var B, C, D, E, F : HugeWord;
I, K, L, P : Integer;
R : Boolean;
begin
// Handle special cases
if HugeWordCompareWord32(A, 1) <= 0 then // A <= 1
exit;
HugeWordInit(B);
HugeWordInit(C);
HugeWordInit(D);
HugeWordInit(E);
HugeWordInit(F);
try
// Shift A left by 8 bits for extra precision
HugeWordAssign(E, A);
HugeWordShl(E, 8);
// Divide algorithm based on Netwon's method for f(y,x) = y <20> x^2
// xest <- (xest + y/xest) / 2
// Initial estimate for xest is 1 shl (HighestSetBit div 2)
K := HugeWordSetBitScanReverse(E);
I := K div 2;
HugeWordAssignOne(C);
HugeWordShl(C, I);
// Iterate until a) estimate converges
// b) the estimate alternates between two values
// c) a maximum number of iterations is reached
// Allow for one iteration per bit in A (plus extra); this is more than
// enough since Newton's method doubles precision with every iteration
// and the initial estimate should be close
L := 8 + K;
I := 0;
P := 0;
R := False;
repeat
HugeWordAssign(B, C); // B = previous xest
HugeWordDivide(E, B, C, D); // C = y/xest
HugeWordAdd(C, B); // C = xest + y/xest
HugeWordShr1(C); // C = (xest + y/xest) / 2
// finish if maximum iteration reached
if I = L then
R := True else
// finish if xest converged on exact value
if HugeWordEquals(B, C) then
R := True
else
begin
// finish if this is the third iteration where difference is one
HugeWordAssign(F, C);
HugeWordSubtract(F, B); // F = difference in xest and previous xest
if HugeWordCompareWord32(F, 1) <= 0 then // F <= 1
if P = 2 then
begin
// xest is alternating between two sequential values
// Take smallest of the two
HugeWordMin(C, B);
R := True
end
else
Inc(P);
end;
Inc(I);
until R;
// Restore precision in result by shifting right
HugeWordShr(C, 4);
HugeWordNormalise(C);
// Return result
HugeWordAssign(A, C);
finally
HugeWordFinalise(F);
HugeWordFinalise(E);
HugeWordFinalise(D);
HugeWordFinalise(C);
HugeWordFinalise(B);
end;
end;
{ HugeWord Extended Euclid }
{ }
{ Pseudocode: }
{ function extended_gcd(a, b) }
{ x := 0 lastx := 1 }
{ y := 1 lasty := 0 }
{ while b <> 0 }
{ quotient := a div b }
{ }
{ temp := b }
{ b := a mod b }
{ a := temp }
{ }
{ temp := x }
{ x := lastx-quotient*x }
{ lastx := temp }
{ }
{ temp := y }
{ y := lasty-quotient*y }
{ lasty := temp }
{ return (lastx, lasty, a) }
{ }
{ Post: R contains GCD(A, B) }
{ X and Y contains values that solve AX + BY = GCD(A, B) }
procedure HugeWordExtendedEuclid(const A, B: HugeWord; var R: HugeWord; var X, Y: HugeInt);
var C, D, T, Q : HugeWord;
I, J, U : HugeInt;
begin
HugeWordInitHugeWord(C, A); // C = A
HugeWordInitHugeWord(D, B); // D = B
HugeWordInit(T);
HugeWordInit(Q);
HugeIntInitOne(I); // I = 1 lastx = 1
HugeIntInitZero(J); // J = 0 lasty = 0
HugeIntInit(U);
try
HugeIntAssignZero(X); // X = 0 x = 0
HugeIntAssignOne(Y); // Y = 1 y = 1
while not HugeWordIsZero(D) do // while b <> 0
begin
HugeWordAssign(T, D); // T = D temp = b
HugeWordDivide(C, D, Q, D); // D = C mod D, Q = C div D Q = quotient
HugeWordAssign(C, T); // C = T a = temp
// x[i+1] = x[i-1] - q[i]*x[i]
HugeIntAssign(U, X); // U = X temp = x
HugeIntMultiplyHugeWord(X, Q); // X = X * Q quotient * x
HugeIntSubtractHugeInt(I, X); // I = I - X lastx - quotient * x
HugeIntAssign(X, I); // X = I x = lastx - quotient * x
HugeIntAssign(I, U); // I = U lastx = temp
HugeIntAssign(U, Y); // U = Y temp = y
HugeIntMultiplyHugeWord(Y, Q); // Y = Y * Q quotient * y
HugeIntSubtractHugeInt(J, Y); // J = J - Y lasty - quotient * y
HugeIntAssign(Y, J); // Y = J y = lasty - quotient * y
HugeIntAssign(J, U); // J = U lasty = temp
end;
HugeIntAssign(X, I); // X = I x = lastx
HugeIntAssign(Y, J); // Y = J y = lasty
HugeWordAssign(R, C); // R = C r = a
finally
HugeIntFinalise(U);
HugeIntFinalise(J);
HugeIntFinalise(I);
HugeWordFinalise(Q);
HugeWordFinalise(T);
HugeWordFinalise(D);
HugeWordFinalise(C);
end;
end;
{ HugeWord Modular Inverse and Mod }
{ Calculates modular inverse(E) mod M using extended Euclidean algorithm }
{ Post: Returns False if modular inverse does not exist }
{ R contains modular inverse(E) mod M if modular inverse exists }
function HugeWordModInv(const E, M: HugeWord; var R: HugeWord): Boolean;
var GCD : HugeWord;
X, Y, F, G : HugeInt;
begin
HugeWordInit(GCD);
HugeIntInit(X);
HugeIntInit(Y);
HugeIntInit(F);
HugeIntInit(G);
try
HugeWordExtendedEuclid(E, M, GCD, X, Y);
if HugeWordIsOne(GCD) then
begin
HugeIntAssign(F, X);
if HugeIntIsNegative(F) then
begin
HugeIntAssignHugeWord(G, M);
HugeIntAddHugeInt(F, G);
end;
HugeWordAssign(R, F.Value);
Result := True;
end
else
Result := False;
finally
HugeIntFinalise(G);
HugeIntFinalise(F);
HugeIntFinalise(Y);
HugeIntFinalise(X);
HugeWordFinalise(GCD);
end;
end;
{ HugeWord Random }
{ Generates a random HugeWord with Size elements. }
{ Pre: Size is number of elements in result }
{ Post: A normalised }
procedure HugeWordRandom(var A: HugeWord; const Size: Integer);
var I : Integer;
P : PWord32;
begin
HugeWordSetSize(A, Size);
if Size <= 0 then
exit;
P := A.Data;
for I := 0 to Size - 1 do
begin
P^ := RandomUniform32;
Inc(P);
end;
HugeWordNormalise(A);
end;
{ HugeWord RandomN }
{ Generates a random HugeWord with value in range 0 to N. }
{ Pre: N is maximum random value }
{ Post: A normalised }
procedure HugeWordRandomN(var A: HugeWord; const N: HugeWord);
var L, I : Integer;
P : PWord32;
begin
L := N.Used;
if L = 0 then
begin
HugeWordAssignZero(A);
exit;
end;
HugeWordSetSize(A, N.Used);
P := A.Data;
for I := 0 to L - 1 do
begin
P^ := RandomUniform32;
Inc(P);
end;
repeat
HugeWordNormalise(A);
if HugeWordCompare(A, N) <= 0 then
exit;
HugeWordShr1(A);
until False;
end;
{ HugeWord Primality testing }
const
PrimeTableCount = 54;
PrimeTable: array[0..PrimeTableCount - 1] of Byte = (
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
223, 227, 229, 233, 239, 241, 251);
{ HugeWord IsPrime Quick Trial }
{ Quick check for primality using trial division of the first few prime }
{ numbers. }
function HugeWordIsPrime_QuickTrial(const A: HugeWord): TPrimality;
var L, I : Integer;
F, G, H : Word32;
C, Q, R : HugeWord;
begin
L := A.Used;
if L = 0 then
Result := pNotPrime else
if L = 1 then
begin
F := HugeWordToWord32(A);
if F = 1 then
Result := pNotPrime else
if F = 2 then
Result := pPrime else
if F and 1 = 0 then
Result := pNotPrime
else
begin
G := Trunc(Sqrt(F)) + 1;
for I := 1 to PrimeTableCount - 1 do
begin
H := PrimeTable[I];
if H > G then
begin
Result := pPrime;
exit;
end;
if F mod H = 0 then
begin
Result := pNotPrime;
exit;
end;
end;
Result := pPotentialPrime;
end;
end
else
if not HugeWordIsOdd(A) then
Result := pNotPrime
else
begin
HugeWordInit(C);
HugeWordInit(Q);
HugeWordInit(R);
try
for I := 1 to PrimeTableCount - 1 do
begin
H := PrimeTable[I];
HugeWordAssignWord32(C, H);
HugeWordDivide(A, C, Q, R);
if HugeWordIsZero(R) then
begin
Result := pNotPrime;
exit;
end;
end;
Result := pPotentialPrime;
finally
HugeWordFinalise(R);
HugeWordFinalise(Q);
HugeWordFinalise(C);
end;
end;
end;
{ HugeWord IsPrime MillerRabin }
{ Check primality using Miller-Rabin: }
{ "pick some a and take a^(n-1) mod n. If you don't get 1, then you know }
{ that n is not prime." }
{ +---+---+---+---+---+---+---+---+----+ }
{ | k |256|342|384|410|512|683|768|1024| }
{ +---+---+---+---+---+---+---+---+----+ }
{ | t |17 |12 |11 |10 |8 |6 |5 |4 | }
{ +---+---+---+---+---+---+---+---+----+ }
{ k = bits in A }
{ t = PrimeTableMRCount sufficient for 2^-100 probability of not being prime }
function HugeWordIsPrime_MillerRabin_Basic(const A: HugeWord): TPrimality;
var I, L, N : Integer;
B, C, D : HugeWord;
begin
HugeWordInit(B);
HugeWordInitHugeWord(C, A);
HugeWordInit(D);
try
HugeWordSubtractWord32(C, 1);
// determine number of checks to do according to number of bits in A
L := HugeWordSetBitScanReverse(A) + 1;
if L >= 1024 then
N := 4 else
if L >= 512 then
N := 8 else
if L >= 256 then
N := 17
else
N := 25;
// do check using first N prime numbers as "a".
// this may be sufficient for actual primality testing for certain A
for I := 0 to N - 1 do
begin
HugeWordAssignWord32(B, PrimeTable[I]);
HugeWordPowerAndMod(D, B, C, A);
if not HugeWordIsOne(D) then
begin
Result := pNotPrime;
exit;
end;
end;
finally
HugeWordFinalise(D);
HugeWordFinalise(C);
HugeWordFinalise(B);
end;
Result := pPotentialPrime;
end;
function HugeWordIsPrime_MillerRabin(const A: HugeWord): TPrimality;
var I, L, N, J, P : Integer;
B, C, D, E, X : HugeWord;
begin
HugeWordInit(B);
HugeWordInitHugeWord(C, A);
HugeWordInit(D);
HugeWordInit(E);
HugeWordInit(X);
try
HugeWordSubtractWord32(C, 1);
// determine number of checks to do according to number of bits in A
L := HugeWordSetBitScanReverse(A) + 1;
if L >= 1024 then
N := 4 else
if L >= 512 then
N := 8 else
if L >= 256 then
N := 17
else
N := 25;
// calculate P and E so that C = A - 1 = 2^P * E
HugeWordAssign(E, C); // E = A - 1
P := 0;
while HugeWordIsEven(E) do
begin
Inc(P);
HugeWordShr1(E);
end;
// here C = A - 1 = 2^P * E
// do check using first N prime numbers as "a".
// this may be sufficient for actual primality testing for certain A
for I := 0 to N - 1 do
begin
HugeWordAssignWord32(B, PrimeTable[I]);
// X = B^E mod A
HugeWordPowerAndMod(X, B, E, A);
if HugeWordIsOne(X) or HugeWordEquals(X, C) then
continue;
for J := 1 to P - 1 do
begin
HugeWordMultiply(D, X, X); // D = X^2
HugeWordMod(D, A, X); // X = X^2 mod A
if HugeWordIsOne(X) then
begin
Result := pNotPrime;
exit;
end;
if HugeWordEquals(X, C) then // if X = A - 1
break;
end;
if HugeWordEquals(X, C) then // if X = A - 1
continue;
Result := pNotPrime;
exit;
end;
finally
HugeWordFinalise(D);
HugeWordFinalise(C);
HugeWordFinalise(B);
HugeWordFinalise(E);
HugeWordFinalise(X);
end;
Result := pPotentialPrime;
end;
{ HugeWord IsPrime }
function HugeWordIsPrime(const A: HugeWord): TPrimality;
begin
Result := HugeWordIsPrime_QuickTrial(A);
if Result <> pPotentialPrime then
exit;
Result := HugeWordIsPrime_MillerRabin(A);
end;
{ HugeWord NextPotentialPrime }
{ Returns the next potential prime after A. }
{ Returns A = 0 if process was aborted by callback procedure. }
procedure HugeWordNextPotentialPrime(var A: HugeWord;
const CallbackProc: THugeWordCallbackProc;
const CallbackData: Integer);
begin
if not HugeWordIsOdd(A) then
HugeWordAddWord32(A, 1)
else
HugeWordAddWord32(A, 2);
while HugeWordIsPrime(A) = pNotPrime do
begin
if Assigned(CallbackProc) then
if not CallbackProc(CallbackData) then
begin
// aborted
HugeWordInitZero(A);
exit;
end;
HugeWordAddWord32(A, 2);
end;
end;
{ }
{ HugeInt }
{ }
procedure HugeIntInit(out A: HugeInt);
begin
A.Sign := 0;
HugeWordInit(A.Value);
end;
procedure HugeIntFinalise(var A: HugeInt);
begin
HugeWordFinalise(A.Value);
end;
procedure HugeIntClearAndFinalise(var A: HugeInt);
begin
HugeWordClearAndFinalise(A.Value);
end;
{ HugeIntNormalise }
{ A 'normalised' HugeInt has a normalised HugeWord Value and has a Sign of }
{ zero if the Value is zero, otherwise a Sign of +1 or -1 to indicate the }
{ sign of Value. }
procedure HugeIntNormalise(var A: HugeInt);
begin
HugeWordNormalise(A.Value);
if HugeWordIsZero(A.Value) then
A.Sign := 0;
end;
procedure HugeIntInitZero(out A: HugeInt);
begin
HugeIntInit(A);
end;
procedure HugeIntInitOne(out A: HugeInt);
begin
HugeIntInit(A);
HugeIntAssignOne(A);
end;
procedure HugeIntInitMinusOne(out A: HugeInt);
begin
HugeIntInit(A);
HugeIntAssignMinusOne(A);
end;
procedure HugeIntInitWord32(out A: HugeInt; const B: Word32);
begin
HugeIntInit(A);
HugeIntAssignWord32(A, B);
end;
procedure HugeIntInitInt32(out A: HugeInt; const B: Int32);
begin
HugeIntInit(A);
HugeIntAssignInt32(A, B);
end;
procedure HugeIntInitInt64(out A: HugeInt; const B: Int64);
begin
HugeIntInit(A);
HugeIntAssignInt64(A, B);
end;
procedure HugeIntInitDouble(out A: HugeInt; const B: Double);
begin
HugeIntInit(A);
HugeIntAssignDouble(A, B);
end;
procedure HugeIntInitHugeWord(out A: HugeInt; const B: HugeWord);
begin
if HugeWordIsZero(B) then
HugeIntInit(A)
else
begin
A.Sign := 1;
HugeWordInitHugeWord(A.Value, B);
end;
end;
procedure HugeIntInitHugeInt(out A: HugeInt; const B: HugeInt);
begin
A.Sign := B.Sign;
HugeWordInitHugeWord(A.Value, B.Value);
end;
procedure HugeIntAssignZero(var A: HugeInt);
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end;
procedure HugeIntAssignOne(var A: HugeInt);
begin
A.Sign := 1;
HugeWordAssignOne(A.Value);
end;
procedure HugeIntAssignMinusOne(var A: HugeInt);
begin
A.Sign := -1;
HugeWordAssignOne(A.Value);
end;
procedure HugeIntAssignWord32(var A: HugeInt; const B: Word32);
begin
if B = 0 then
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end
else
begin
A.Sign := 1;
HugeWordAssignWord32(A.Value, B);
end;
end;
procedure HugeIntAssignInt32(var A: HugeInt; const B: Int32);
begin
if B = 0 then
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end else
if B < 0 then
begin
A.Sign := -1;
HugeWordAssignWord32(A.Value, Word32(-Int64(B)));
end
else
begin
A.Sign := 1;
HugeWordAssignInt32(A.Value, B);
end;
end;
procedure HugeIntAssignInt64(var A: HugeInt; const B: Int64);
var T : Int64;
begin
if B = 0 then
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end else
if B < 0 then
begin
A.Sign := -1;
if B = MinInt64 {-$8000000000000000} then
begin
HugeWordSetSize(A.Value, 2);
HugeWordSetElement(A.Value, 0, $00000000);
HugeWordSetElement(A.Value, 1, $80000000);
end
else
begin
T := -B;
HugeWordAssignInt64(A.Value, T);
end;
end
else
begin
A.Sign := 1;
HugeWordAssignInt64(A.Value, B);
end;
end;
procedure HugeIntAssignDouble(var A: HugeInt; const B: Double);
begin
HugeWordAssignDouble(A.Value, Abs(B));
if HugeWordIsZero(A.Value) then
A.Sign := 0
else
if B < 0.0 then
A.Sign := -1
else
A.Sign := 1;
end;
procedure HugeIntAssignHugeWord(var A: HugeInt; const B: HugeWord);
begin
if HugeWordIsZero(B) then
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end
else
begin
A.Sign := 1;
HugeWordAssign(A.Value, B);
end;
end;
procedure HugeIntAssignHugeWordNegated(var A: HugeInt; const B: HugeWord);
begin
if HugeWordIsZero(B) then
begin
A.Sign := 0;
HugeWordAssignZero(A.Value);
end
else
begin
A.Sign := -1;
HugeWordAssign(A.Value, B);
end;
end;
procedure HugeIntAssign(var A: HugeInt; const B: HugeInt);
begin
A.Sign := B.Sign;
HugeWordAssign(A.Value, B.Value);
end;
procedure HugeIntSwap(var A, B: HugeInt);
var C : HugeInt;
begin
HugeIntInitHugeInt(C, A); // C := A
try
HugeIntAssign(A, B); // A := B
HugeIntAssign(B, C); // B := C
finally
HugeIntFinalise(C);
end;
end;
function HugeIntIsZero(const A: HugeInt): Boolean;
begin
Result := A.Sign = 0;
end;
function HugeIntIsNegative(const A: HugeInt): Boolean;
begin
Result := A.Sign < 0;
end;
function HugeIntIsNegativeOrZero(const A: HugeInt): Boolean;
begin
Result := A.Sign <= 0;
end;
function HugeIntIsPositive(const A: HugeInt): Boolean;
begin
Result := A.Sign > 0;
end;
function HugeIntIsPositiveOrZero(const A: HugeInt): Boolean;
begin
Result := A.Sign >= 0;
end;
function HugeIntIsOne(const A: HugeInt): Boolean;
begin
Result := (A.Sign > 0) and HugeWordIsOne(A.Value);
end;
function HugeIntIsMinusOne(const A: HugeInt): Boolean;
begin
Result := (A.Sign < 0) and HugeWordIsOne(A.Value);
end;
function HugeIntIsOdd(const A: HugeInt): Boolean;
begin
Result := HugeWordIsOdd(A.Value);
end;
function HugeIntIsEven(const A: HugeInt): Boolean;
begin
Result := HugeWordIsOdd(A.Value);
end;
function HugeIntIsWord32Range(const A: HugeInt): Boolean;
begin
if A.Sign = 0 then
Result := True else
if A.Sign < 0 then
Result := False
else
Result := HugeWordGetSize(A.Value) <= 1;
end;
function HugeIntIsWord64Range(const A: HugeInt): Boolean;
begin
if A.Sign = 0 then
Result := True else
if A.Sign < 0 then
Result := False
else
Result := HugeWordGetSize(A.Value) <= 2;
end;
function HugeIntIsWord128Range(const A: HugeInt): Boolean;
begin
if A.Sign = 0 then
Result := True else
if A.Sign < 0 then
Result := False
else
Result := HugeWordGetSize(A.Value) <= 4;
end;
function HugeIntIsWord256Range(const A: HugeInt): Boolean;
begin
if A.Sign = 0 then
Result := True else
if A.Sign < 0 then
Result := False
else
Result := HugeWordGetSize(A.Value) <= 8;
end;
function HugeIntIsInt32Range(const A: HugeInt): Boolean;
begin
if A.Sign = 0 then
Result := True else
if HugeWordGetSize(A.Value) > 1 then
Result := False
else
if A.Sign > 0 then
Result := HugeWordIsInt32Range(A.Value)
else
Result := HugeWordGetElement(A.Value, 0) <= $80000000;
end;
function HugeIntIsInt64Range(const A: HugeInt): Boolean;
var F : Word32;
begin
if A.Sign = 0 then
Result := True
else
begin
F := HugeWordGetSize(A.Value);
if F = 1 then
Result := True else
if F > 2 then
Result := False
else
if A.Sign > 0 then
Result := HugeWordIsInt64Range(A.Value)
else
begin
F := HugeWordGetElement(A.Value, 1);
if F > $80000000 then
Result := False else
if F < $80000000 then
Result := True
else
Result := HugeWordGetElement(A.Value, 0) = $00000000;
end;
end;
end;
function HugeIntIsInt128Range(const A: HugeInt): Boolean;
var F : Word32;
begin
if A.Sign = 0 then
Result := True
else
begin
F := HugeWordGetSize(A.Value);
if F < 4 then
Result := True else
if F > 4 then
Result := False
else
if A.Sign > 0 then
Result := HugeWordIsInt128Range(A.Value)
else
begin
F := HugeWordGetElement(A.Value, 3);
if F > $80000000 then
Result := False else
if F < $80000000 then
Result := True
else
Result := (HugeWordGetElement(A.Value, 0) = $00000000)
and (HugeWordGetElement(A.Value, 1) = $00000000)
and (HugeWordGetElement(A.Value, 2) = $00000000);
end;
end;
end;
function HugeIntIsInt256Range(const A: HugeInt): Boolean;
var F : Word32;
begin
if A.Sign = 0 then
Result := True
else
begin
F := HugeWordGetSize(A.Value);
if F < 8 then
Result := True else
if F > 8 then
Result := False
else
if A.Sign > 0 then
Result := HugeWordIsInt256Range(A.Value)
else
begin
F := HugeWordGetElement(A.Value, 7);
if F > $80000000 then
Result := False else
if F < $80000000 then
Result := True
else
Result := (HugeWordGetElement(A.Value, 0) = $00000000)
and (HugeWordGetElement(A.Value, 1) = $00000000)
and (HugeWordGetElement(A.Value, 2) = $00000000)
and (HugeWordGetElement(A.Value, 3) = $00000000)
and (HugeWordGetElement(A.Value, 4) = $00000000)
and (HugeWordGetElement(A.Value, 5) = $00000000)
and (HugeWordGetElement(A.Value, 6) = $00000000);
end;
end;
end;
function HugeIntSign(const A: HugeInt): Integer;
begin
Result := A.Sign;
end;
procedure HugeIntNegate(var A: HugeInt);
begin
A.Sign := -A.Sign;
end;
function HugeIntAbsInPlace(var A: HugeInt): Boolean;
begin
if A.Sign < 0 then
begin
A.Sign := 1;
Result := True;
end
else
Result := False;
end;
function HugeIntAbs(const A: HugeInt; var B: HugeWord): Boolean;
begin
HugeWordAssign(B, A.Value);
Result := A.Sign < 0;
end;
function HugeIntToWord32(const A: HugeInt): Word32;
begin
{$IFOPT R+}
if (A.Sign < 0) or not HugeWordIsWord32Range(A.Value) then
RaiseRangeError;
{$ENDIF}
Result := HugeWordToWord32(A.Value);
end;
function HugeIntToInt32(const A: HugeInt): Int32;
begin
{$IFOPT R+}
if ((A.Sign > 0) and (HugeWordCompareWord32(A.Value, $7FFFFFFF) > 0)) or
((A.Sign < 0) and (HugeWordCompareWord32(A.Value, $80000000) > 0)) then
RaiseRangeError;
{$ENDIF}
if A.Sign > 0 then
Result := HugeWordToWord32(A.Value) else
if A.Sign < 0 then
begin
// Delphi5/7 incorrectly raises an exception if the following is done
// in one statement, i.e.
// Result := -HugeWordToWord32(A.Value)
Result := HugeWordToWord32(A.Value);
Result := -Result;
end
else
Result := 0;
end;
function HugeIntToInt64(const A: HugeInt): Int64;
begin
{$IFOPT R+}
if A.Value.Used > 2 then
RaiseRangeError else
if A.Value.Used = 2 then
if A.Sign > 0 then
begin
if HugeWordGetElement(A.Value, 1) > $7FFFFFFF then
RaiseRangeError;
end else
if A.Sign < 0 then
begin
if HugeWordGetElement(A.Value, 1) > $80000000 then
RaiseRangeError;
if (HugeWordGetElement(A.Value, 1) = $80000000) and
(HugeWordGetElement(A.Value, 0) > $00000000) then
RaiseRangeError;
end;
{$ENDIF}
if A.Sign > 0 then
Result := HugeWordToInt64(A.Value) else
if A.Sign < 0 then
begin
if (A.Value.Used = 2) and
(HugeWordGetElement(A.Value, 1) = $80000000) and
(HugeWordGetElement(A.Value, 0) = $00000000) then
Result := MinInt64 { -$8000000000000000 }
else
begin
{$IFDEF DELPHI5}
// Delphi5 incorrectly raises an overflow with 7FFFFFFFFFFFFFFF
if (A.Value.Used = 2) and
(HugeWordGetElement(A.Value, 1) = $7FFFFFFF) and
(HugeWordGetElement(A.Value, 0) = $FFFFFFFF) then
Result := -$7FFFFFFFFFFFFFFF
else
Result := -HugeWordToInt64(A.Value);
{$ELSE}
Result := -HugeWordToInt64(A.Value);
{$ENDIF}
end;
end
else
Result := 0;
end;
function HugeIntToDouble(const A: HugeInt): Double;
var V : Double;
begin
V := HugeWordToDouble(A.Value);
if A.Sign < 0 then
V := -V;
Result := V;
end;
function HugeIntEqualsWord32(const A: HugeInt; const B: Word32): Boolean;
begin
if A.Sign < 0 then
Result := False else
if not HugeWordIsWord32Range(A.Value) then
Result := False
else
Result := HugeWordToWord32(A.Value) = B;
end;
function HugeIntEqualsInt32(const A: HugeInt; const B: Int32): Boolean;
begin
if A.Sign < 0 then
if B >= 0 then
Result := False
else
Result := HugeWordEqualsWord32(A.Value, Word32(-Int64(B)))
else
Result := HugeWordEqualsInt32(A.Value, B);
end;
function HugeIntEqualsInt64(const A: HugeInt; const B: Int64): Boolean;
begin
if A.Sign < 0 then
if B >= 0 then
Result := False
else
begin
if B = MinInt64 { -$8000000000000000 } then
begin
if HugeWordGetSize(A.Value) <> 2 then
Result := False
else
Result :=
(HugeWordGetElement(A.Value, 0) = $00000000) and
(HugeWordGetElement(A.Value, 1) = $80000000);
end
else
Result := HugeWordEqualsInt64(A.Value, -B);
end
else
Result := HugeWordEqualsInt64(A.Value, B);
end;
function HugeIntEqualsHugeInt(const A, B: HugeInt): Boolean;
begin
if A.Sign <> B.Sign then
Result := False else
if A.Sign = 0 then
Result := True
else
Result := HugeWordEquals(A.Value, B.Value);
end;
function HugeIntCompareWord32(const A: HugeInt; const B: Word32): Integer;
begin
if A.Sign < 0 then
Result := -1 else
if A.Sign = 0 then
if B = 0 then
Result := 0
else
Result := -1
else
Result := HugeWordCompareWord32(A.Value, B);
end;
function HugeIntCompareInt32(const A: HugeInt; const B: Int32): Integer;
begin
if A.Sign < 0 then
if B >= 0 then
Result := -1
else
Result := -HugeWordCompareWord32(A.Value, Word32(-Int64(B)))
else
if A.Sign = 0 then
if B < 0 then
Result := 1 else
if B = 0 then
Result := 0
else
Result := -1
else
Result := HugeWordCompareInt32(A.Value, B);
end;
function HugeIntCompareInt64(const A: HugeInt; const B: Int64): Integer;
var L : Integer;
F, G : Word32;
begin
if A.Sign < 0 then
if B >= 0 then
Result := -1
else
begin
if B = MinInt64 { -$8000000000000000 } then
begin
L := HugeWordGetSize(A.Value);
if L < 2 then
Result := 1 else
if L > 2 then
Result := -1
else
begin
F := HugeWordGetElement(A.Value, 0);
G := HugeWordGetElement(A.Value, 1);
if G > $80000000 then
Result := -1 else
if G < $80000000 then
Result := 1
else
if F > $00000000 then
Result := -1
else
Result := 0;
end;
end
else
Result := -HugeWordCompareInt64(A.Value, -B);
end
else
if A.Sign = 0 then
if B < 0 then
Result := 1 else
if B = 0 then
Result := 0
else
Result := -1
else
Result := HugeWordCompareInt64(A.Value, B);
end;
function HugeIntCompareHugeInt(const A, B: HugeInt): Integer;
begin
if A.Sign < 0 then
if B.Sign >= 0 then
Result := -1
else
Result := -HugeWordCompare(A.Value, B.Value)
else
if A.Sign = 0 then
if B.Sign < 0 then
Result := 1 else
if B.Sign = 0 then
Result := 0
else
Result := -1
else
if B.Sign <= 0 then
Result := 1
else
Result := HugeWordCompare(A.Value, B.Value);
end;
{ HugeInt CompareHugeIntAbs }
{ Compares the absolute values of two HugeInts. }
function HugeIntCompareHugeIntAbs(const A, B: HugeInt): Integer;
begin
if A.Sign = 0 then
if B.Sign = 0 then
Result := 0
else
Result := -1
else
if B.Sign = 0 then
Result := 1
else
Result := HugeWordCompare(A.Value, B.Value);
end;
procedure HugeIntMin(var A: HugeInt; const B: HugeInt);
begin
if HugeIntCompareHugeInt(A, B) <= 0 then
exit;
HugeIntAssign(A, B);
end;
procedure HugeIntMax(var A: HugeInt; const B: HugeInt);
begin
if HugeIntCompareHugeInt(A, B) >= 0 then
exit;
HugeIntAssign(A, B);
end;
procedure HugeIntAddWord32(var A: HugeInt; const B: Word32);
var C : Integer;
begin
if B = 0 then
exit;
if A.Sign = 0 then
HugeIntAssignWord32(A, B) else
if A.Sign < 0 then
begin
C := HugeWordSubtractWord32(A.Value, B);
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := 1;
end
else
HugeWordAddWord32(A.Value, B);
end;
procedure HugeIntAddInt32(var A: HugeInt; const B: Int32);
var C : Integer;
begin
if B = 0 then
exit;
if A.Sign = 0 then
HugeIntAssignInt32(A, B)
else
if ((B > 0) and (A.Sign < 0)) or
((B < 0) and (A.Sign > 0)) then
begin
C := HugeWordSubtractWord32(A.Value, Abs(B));
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := -A.Sign;
end
else
HugeWordAddWord32(A.Value, Abs(B));
end;
procedure HugeIntAddHugeInt(var A: HugeInt; const B: HugeInt);
var C : Integer;
begin
if B.Sign = 0 then
exit;
if A.Sign = 0 then
HugeIntAssign(A, B)
else
if A.Sign <> B.Sign then
begin
C := HugeWordSubtract(A.Value, B.Value);
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := -A.Sign;
end
else
HugeWordAdd(A.Value, B.Value);
end;
procedure HugeIntInc(var A: HugeInt);
begin
HugeIntAddWord32(A, 1);
end;
procedure HugeIntSubtractWord32(var A: HugeInt; const B: Word32);
var C : Integer;
begin
if B = 0 then
exit;
if A.Sign = 0 then
begin
A.Sign := -1;
HugeWordInitWord32(A.Value, B);
end else
if A.Sign < 0 then
HugeWordAddWord32(A.Value, B)
else
begin
C := HugeWordSubtractWord32(A.Value, B);
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := -1;
end;
end;
procedure HugeIntSubtractInt32(var A: HugeInt; const B: Int32);
var C : Integer;
begin
if B = 0 then
exit;
if A.Sign = 0 then
begin
HugeIntAssignInt32(A, B);
HugeIntNegate(A);
end
else
if ((B > 0) and (A.Sign < 0)) or
((B < 0) and (A.Sign > 0)) then
HugeWordAddWord32(A.Value, Abs(B))
else
begin
C := HugeWordSubtractWord32(A.Value, Abs(B));
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := -A.Sign;
end;
end;
procedure HugeIntSubtractHugeInt(var A: HugeInt; const B: HugeInt);
var C : Integer;
begin
if B.Sign = 0 then
exit;
if A.Sign = 0 then
begin
HugeIntAssign(A, B);
A.Sign := -B.Sign;
end
else
if A.Sign <> B.Sign then
HugeWordAdd(A.Value, B.Value)
else
begin
C := HugeWordSubtract(A.Value, B.Value);
if C = 0 then
HugeIntAssignZero(A) else
if C < 0 then
A.Sign := -A.Sign;
end;
end;
procedure HugeIntDec(var A: HugeInt);
begin
HugeIntSubtractWord32(A, 1);
end;
procedure HugeIntMultiplyWord8(var A: HugeInt; const B: Byte);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
HugeWordMultiplyWord8(A.Value, B);
end;
procedure HugeIntMultiplyWord16(var A: HugeInt; const B: Word);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
HugeWordMultiplyWord16(A.Value, B);
end;
procedure HugeIntMultiplyWord32(var A: HugeInt; const B: Word32);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
HugeWordMultiplyWord32(A.Value, B);
end;
procedure HugeIntMultiplyInt8(var A: HugeInt; const B: ShortInt);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
begin
HugeWordMultiplyWord8(A.Value, Abs(B));
if ((B < 0) and (A.Sign > 0)) or
((B > 0) and (A.Sign < 0)) then
A.Sign := -1
else
A.Sign := 1;
end;
end;
procedure HugeIntMultiplyInt16(var A: HugeInt; const B: SmallInt);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
begin
HugeWordMultiplyWord16(A.Value, Abs(B));
if ((B < 0) and (A.Sign > 0)) or
((B > 0) and (A.Sign < 0)) then
A.Sign := -1
else
A.Sign := 1;
end;
end;
procedure HugeIntMultiplyInt32(var A: HugeInt; const B: Int32);
begin
if A.Sign = 0 then
exit;
if B = 0 then
HugeIntAssignZero(A)
else
begin
HugeWordMultiplyWord32(A.Value, Abs(B));
if ((B < 0) and (A.Sign > 0)) or
((B > 0) and (A.Sign < 0)) then
A.Sign := -1
else
A.Sign := 1;
end;
end;
procedure HugeIntMultiplyHugeWord(var A: HugeInt; const B: HugeWord);
begin
if A.Sign = 0 then
exit;
if HugeWordIsZero(B) then
HugeIntAssignZero(A)
else
HugeWordMultiply(A.Value, A.Value, B);
end;
procedure HugeIntMultiplyHugeInt(var A: HugeInt; const B: HugeInt);
begin
if A.Sign = 0 then
exit;
if B.Sign = 0 then
HugeIntAssignZero(A)
else
begin
HugeWordMultiply(A.Value, A.Value, B.Value);
if A.Sign <> B.Sign then
A.Sign := -1
else
A.Sign := 1;
end;
end;
procedure HugeIntSqr(var A: HugeInt);
begin
if A.Sign = 0 then
exit;
A.Sign := 1;
HugeWordSqr(A.Value, A.Value);
end;
// Truncated division:
// Qt = Trunc(A/B) Qt = Trunc(1000/3) = 333
// Rt = A - B * Qt Rt = -1000 - (3 * -333) = -1000 + 999 = -1
// Sign of Rt always Sign of A
// Floor division:
// Qf = Floor(A/B) = Qt - I
// Rf = Rt + I * B
// I = if Sign(Rt) = -Sign(B) then 1 else 0
// Euclidian division:
// Qf = Floor(A/B) = Qt - I
// Rf = Rt + I * B
// 0 <= Rf < Abs(B)
// I = if Rt >= 0 then 0 else if B > 0 then 1 else -1
procedure HugeIntDivideWord32(const A: HugeInt; const B: Word32; var Q: HugeInt; out R: Word32);
begin
if B = 0 then
RaiseDivByZeroError;
if A.Sign = 0 then
begin
HugeIntAssignZero(Q);
R := 0;
exit;
end;
HugeWordDivideWord32(A.Value, B, Q.Value, R);
if HugeWordIsZero(Q.Value) then
Q.Sign := 0
else
Q.Sign := A.Sign;
end;
procedure HugeIntDivideInt32(const A: HugeInt; const B: Int32; var Q: HugeInt; out R: Int32);
var C : Word32;
begin
if B = 0 then
RaiseDivByZeroError;
if A.Sign = 0 then
begin
HugeIntAssignZero(Q);
R := 0;
exit;
end;
HugeWordDivideWord32(A.Value, Abs(B), Q.Value, C);
if HugeWordIsZero(Q.Value) then
Q.Sign := 0 else
if ((B > 0) and (A.Sign < 0)) or
((B < 0) and (A.Sign > 0)) then
Q.Sign := -1
else
Q.Sign := 1;
R := Int32(C);
end;
/// See https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
// Q = Trunc(A/B)
// Also known as truncated division
// Remainder has same sign as dividend
// C++, C#, Go, Java % operators
procedure HugeIntDivideHugeInt_T(const A, B: HugeInt; var Q, R: HugeInt);
begin
if B.Sign = 0 then
RaiseDivByZeroError;
if A.Sign = 0 then
begin
HugeIntAssignZero(Q);
HugeIntAssignZero(R);
exit;
end;
HugeWordDivide(A.Value, B.Value, Q.Value, R.Value);
if HugeWordIsZero(Q.Value) then
begin
Q.Sign := 0;
R.Sign := A.Sign;
exit;
end;
if HugeWordIsZero(R.Value) then
begin
R.Sign := 0;
if A.Sign <> B.Sign then
Q.Sign := -1
else
Q.Sign := 1;
exit;
end;
R.Sign := A.Sign;
if A.Sign <> B.Sign then
Q.Sign := -1
else
Q.Sign := 1;
end;
// Q = Floor(A/B)
// Also known as Knuth method
// Remainder has same sign as divisor
// R = Python % operator
procedure HugeIntDivideHugeInt_F(const A, B: HugeInt; var Q, R: HugeInt);
var
L : Integer;
begin
HugeIntDivideHugeInt_T(A, B, Q, R);
if R.Sign = -B.Sign then
L := 1
else
L := 0;
if L = 1 then
begin
HugeIntDec(Q);
HugeIntAddHugeInt(R, B);
end;
end;
// Euclidian division
// Remainder always positive
procedure HugeIntDivideHugeInt_E(const A, B: HugeInt; var Q, R: HugeInt);
var
L : Integer;
begin
HugeIntDivideHugeInt_T(A, B, Q, R);
if R.Sign >= 0 then
L := 0
else
if B.Sign > 0 then
L := 1
else
L := -1;
if L <> 0 then
begin
HugeIntSubtractInt32(Q, L);
if L < 0 then
HugeIntSubtractHugeInt(R, B)
else
HugeIntAddHugeInt(R, B)
end;
end;
procedure HugeIntDivideHugeInt(const A, B: HugeInt; var Q, R: HugeInt);
begin
if B.Sign = 0 then
RaiseDivByZeroError;
if A.Sign = 0 then
begin
HugeIntAssignZero(Q);
HugeIntAssignZero(R);
exit;
end;
HugeWordDivide(A.Value, B.Value, Q.Value, R.Value);
if HugeWordIsZero(Q.Value) then
Q.Sign := 0 else
if A.Sign <> B.Sign then
Q.Sign := -1
else
Q.Sign := 1;
if HugeWordIsZero(R.Value) then
R.Sign := 0
else
R.Sign := 1;
end;
procedure HugeIntMod_T(const A, B: HugeInt; var R: HugeInt);
var Q : HugeInt;
begin
HugeIntInit(Q);
try
HugeIntDivideHugeInt_T(A, B, Q, R);
finally
HugeIntFinalise(Q);
end;
end;
procedure HugeIntMod_F(const A, B: HugeInt; var R: HugeInt);
var Q : HugeInt;
begin
HugeIntInit(Q);
try
HugeIntDivideHugeInt_F(A, B, Q, R);
finally
HugeIntFinalise(Q);
end;
end;
procedure HugeIntMod_E(const A, B: HugeInt; var R: HugeInt);
var Q : HugeInt;
begin
HugeIntInit(Q);
try
HugeIntDivideHugeInt_E(A, B, Q, R);
finally
HugeIntFinalise(Q);
end;
end;
procedure HugeIntMod(const A, B: HugeInt; var R: HugeInt);
var Q : HugeInt;
begin
HugeIntInit(Q);
try
HugeIntDivideHugeInt(A, B, Q, R);
finally
HugeIntFinalise(Q);
end;
end;
procedure HugeIntPower(var A: HugeInt; const B: Word32);
begin
if B = 0 then
begin
HugeIntAssignOne(A);
exit;
end;
if HugeIntIsZero(A) or HugeIntIsOne(A) then
exit;
if B = 1 then
exit;
if B = 2 then
begin
HugeIntSqr(A);
exit;
end;
HugeWordPower(A.Value, B);
if (A.Sign < 0) and (B and 1 = 0) then
A.Sign := 1;
end;
function HugeIntToStrB(const A: HugeInt): UTF8String;
var S : UTF8String;
begin
if A.Sign = 0 then
Result := '0'
else
begin
S := HugeWordToStrB(A.Value);
if A.Sign < 0 then
Result := '-' + S
else
Result := S;
end;
end;
function HugeIntToStrU(const A: HugeInt): UnicodeString;
var S : UnicodeString;
begin
if A.Sign = 0 then
Result := '0'
else
begin
S := HugeWordToStrU(A.Value);
if A.Sign < 0 then
Result := '-' + S
else
Result := S;
end;
end;
procedure StrToHugeIntB(const A: RawByteString; var R: HugeInt);
var B : RawByteString;
begin
if A = '' then
RaiseConvertError;
if A[1] = '-' then
begin
R.Sign := -1;
B := Copy(A, 2, Length(A) - 1);
end
else
begin
R.Sign := 1;
B := A;
end;
StrToHugeWordB(B, R.Value);
if HugeWordIsZero(R.Value) then
R.Sign := 0;
end;
procedure StrToHugeIntU(const A: UnicodeString; var R: HugeInt);
var B : UnicodeString;
begin
if A = '' then
RaiseConvertError;
if A[1] = '-' then
begin
R.Sign := -1;
B := Copy(A, 2, Length(A) - 1);
end
else
begin
R.Sign := 1;
B := A;
end;
StrToHugeWordU(B, R.Value);
if HugeWordIsZero(R.Value) then
R.Sign := 0;
end;
function HugeIntToHexB(const A: HugeInt): UTF8String;
var S : RawByteString;
begin
if A.Sign = 0 then
Result := '00000000'
else
begin
S := HugeWordToHexB(A.Value);
if A.Sign < 0 then
Result := '-' + S
else
Result := S;
end;
end;
procedure HexToHugeIntB(const A: RawByteString; var R: HugeInt);
var B : RawByteString;
begin
if A = '' then
RaiseConvertError;
if A[1] = '-' then
begin
R.Sign := -1;
B := Copy(A, 2, Length(A) - 1);
end
else
begin
R.Sign := 1;
B := A;
end;
HexToHugeWordB(B, R.Value);
if HugeWordIsZero(R.Value) then
R.Sign := 0;
end;
procedure HugeIntISqrt(var A: HugeInt);
begin
if A.Sign = 0 then
exit;
if A.Sign < 0 then
RaiseInvalidOpError;
HugeWordISqrt(A.Value);
end;
procedure HugeIntRandom(var A: HugeInt; const Size: Integer);
begin
HugeWordRandom(A.Value, Size);
if HugeWordIsZero(A.Value) then
A.Sign := 0 else
if RandomBoolean then
A.Sign := 1
else
A.Sign := -1;
end;
{ }
{ HugeInt class }
{ }
constructor THugeInt.Create;
begin
inherited Create;
HugeIntInit(FValue);
end;
constructor THugeInt.Create(const A: Int64);
begin
inherited Create;
HugeIntInitInt64(FValue, A);
end;
constructor THugeInt.Create(const A: THugeInt);
begin
Assert(Assigned(A));
inherited Create;
HugeIntInitHugeInt(FValue, A.FValue);
end;
destructor THugeInt.Destroy;
begin
HugeIntFinalise(FValue);
inherited Destroy;
end;
procedure THugeInt.AssignZero;
begin
HugeIntAssignZero(FValue);;
end;
procedure THugeInt.AssignOne;
begin
HugeIntAssignOne(FValue);;
end;
procedure THugeInt.AssignMinusOne;
begin
HugeIntAssignMinusOne(FValue);;
end;
procedure THugeInt.Assign(const A: Int64);
begin
HugeIntAssignInt64(FValue, A);
end;
procedure THugeInt.Assign(const A: THugeInt);
begin
HugeIntAssign(FValue, A.FValue);
end;
function THugeInt.IsZero: Boolean;
begin
Result := HugeIntIsZero(FValue);
end;
function THugeInt.IsNegative: Boolean;
begin
Result := HugeIntIsNegative(FValue);
end;
function THugeInt.IsPositive: Boolean;
begin
Result := HugeIntIsPositive(FValue);
end;
function THugeInt.IsOne: Boolean;
begin
Result := HugeIntIsOne(FValue);
end;
function THugeInt.IsMinusOne: Boolean;
begin
Result := HugeIntIsMinusOne(FValue);
end;
function THugeInt.IsOdd: Boolean;
begin
Result := HugeIntIsOdd(FValue);
end;
function THugeInt.IsEven: Boolean;
begin
Result := HugeIntIsEven(FValue);
end;
function THugeInt.Sign: Integer;
begin
Result := HugeIntSign(FValue);
end;
procedure THugeInt.Negate;
begin
HugeIntNegate(FValue);
end;
procedure THugeInt.Abs;
begin
HugeIntAbsInPlace(FValue);
end;
function THugeInt.ToWord32: Word32;
begin
Result := HugeIntToWord32(FValue);
end;
function THugeInt.ToInt32: Int32;
begin
Result := HugeIntToInt32(FValue);
end;
function THugeInt.ToInt64: Int64;
begin
Result := HugeIntToInt64(FValue);
end;
function THugeInt.EqualTo(const A: Word32): Boolean;
begin
Result := HugeIntEqualsWord32(FValue, A);
end;
function THugeInt.EqualTo(const A: Int32): Boolean;
begin
Result := HugeIntEqualsInt32(FValue, A);
end;
function THugeInt.EqualTo(const A: Int64): Boolean;
begin
Result := HugeIntEqualsInt64(FValue, A);
end;
function THugeInt.EqualTo(const A: THugeInt): Boolean;
begin
Assert(Assigned(A));
Result := HugeIntEqualsHugeInt(FValue, A.FValue);
end;
function THugeInt.Compare(const A: Word32): Integer;
begin
Result := HugeIntCompareWord32(FValue, A);
end;
function THugeInt.Compare(const A: Int32): Integer;
begin
Result := HugeIntCompareInt32(FValue, A);
end;
function THugeInt.Compare(const A: Int64): Integer;
begin
Result := HugeIntCompareInt64(FValue, A);
end;
function THugeInt.Compare(const A: THugeInt): Integer;
begin
Assert(Assigned(A));
Result := HugeIntCompareHugeInt(FValue, A.FValue);
end;
procedure THugeInt.Add(const A: Int32);
begin
HugeIntAddInt32(FValue, A);
end;
procedure THugeInt.Add(const A: THugeInt);
begin
HugeIntAddHugeInt(FValue, A.FValue);
end;
procedure THugeInt.Inc;
begin
HugeIntInc(FValue);
end;
procedure THugeInt.Subtract(const A: Int32);
begin
HugeIntSubtractInt32(FValue, A);
end;
procedure THugeInt.Subtract(const A: THugeInt);
begin
HugeIntSubtractHugeInt(FValue, A.FValue);
end;
procedure THugeInt.Dec;
begin
HugeIntDec(FValue);
end;
procedure THugeInt.Multiply(const A: Int32);
begin
HugeIntMultiplyInt32(FValue, A);
end;
procedure THugeInt.Multiply(const A: THugeInt);
begin
HugeIntMultiplyHugeInt(FValue, A.FValue);
end;
procedure THugeInt.Sqr;
begin
HugeIntSqr(FValue);
end;
procedure THugeInt.Divide(const B: Int32; out R: Int32);
begin
HugeIntDivideInt32(FValue, B, FValue, R);
end;
procedure THugeInt.Divide(const B: THugeInt; var R: THugeInt);
begin
HugeIntDivideHugeInt(FValue, B.FValue, FValue, R.FValue);
end;
procedure THugeInt.Power(const B: Word32);
begin
HugeIntPower(FValue, B);
end;
function THugeInt.ToStr: UTF8String;
begin
Result := HugeIntToStrB(FValue);
end;
function THugeInt.ToHex: UTF8String;
begin
Result := HugeIntToHexB(FValue);
end;
procedure THugeInt.AssignStr(const A: RawByteString);
begin
StrToHugeIntB(A, FValue);
end;
procedure THugeInt.AssignHex(const A: RawByteString);
begin
HexToHugeIntB(A, FValue);
end;
procedure THugeInt.ISqrt;
begin
HugeIntISqrt(FValue);
end;
procedure THugeInt.Random(const Size: Integer);
begin
HugeIntRandom(FValue, Size);
end;
{ }
{ Tests }
{ }
{$IFDEF HUGEINT_TEST}
{$ASSERTIONS ON}
procedure Test_HugeWord;
var A, B, C, D : HugeWord;
X, Y : HugeInt;
I : Integer;
S : UTF8String;
F : Word32;
begin
HugeWordInit(A);
HugeWordInit(B);
HugeWordInit(C);
HugeWordInit(D);
HugeIntInit(X);
HugeIntInit(Y);
// Zero
HugeWordAssignZero(A);
Assert(HugeWordGetSize(A) = 0);
Assert(HugeWordIsZero(A));
Assert(HugeWordToWord32(A) = 0);
Assert(HugeWordToInt32(A) = 0);
Assert(HugeWordToInt64(A) = 0);
Assert(HugeWordCompareWord32(A, 0) = 0);
Assert(HugeWordCompareWord32(A, 1) = -1);
Assert(HugeWordCompare(A, A) = 0);
Assert(HugeWordIsWord32Range(A));
Assert(HugeWordIsWord64Range(A));
Assert(HugeWordIsInt32Range(A));
Assert(HugeWordIsInt64Range(A));
Assert(HugeWordIsEven(A));
Assert(not HugeWordIsOdd(A));
Assert(HugeWordToStrB(A) = '0');
Assert(HugeWordToHexB(A) = '00000000');
Assert(HugeWordSetBitScanForward(A) = -1);
Assert(HugeWordSetBitScanReverse(A) = -1);
Assert(HugeWordClearBitScanForward(A) = 0);
Assert(HugeWordClearBitScanReverse(A) = 0);
Assert(HugeWordToDouble(A) = 0.0);
// One
HugeWordAssignOne(A);
Assert(not HugeWordIsEven(A));
Assert(HugeWordIsOdd(A));
Assert(not HugeWordIsZero(A));
Assert(HugeWordIsOne(A));
Assert(HugeWordToInt32(A) = 1);
Assert(HugeWordCompareWord32(A, 0) = 1);
Assert(HugeWordToHexB(A) = '00000001');
Assert(HugeWordSetBitScanForward(A) = 0);
Assert(HugeWordSetBitScanReverse(A) = 0);
Assert(HugeWordClearBitScanForward(A) = 1);
Assert(HugeWordClearBitScanReverse(A) = 1);
Assert(HugeWordToDouble(A) = 1.0);
// $FFFFFFFF
HugeWordAssignZero(A);
HugeWordAddWord32(A, $FFFFFFFF);
Assert(HugeWordGetSize(A) = 1);
Assert(HugeWordGetElement(A, 0) = $FFFFFFFF);
Assert(HugeWordIsWord32Range(A));
Assert(not HugeWordIsInt32Range(A));
Assert(HugeWordIsInt64Range(A));
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordToInt64(A) = $FFFFFFFF);
Assert(not HugeWordIsZero(A));
Assert(HugeWordCompareWord32(A, 0) = 1);
HugeWordAddWord32(A, $FFFFFFFF);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFE) and (HugeWordGetElement(A, 1) = 1));
Assert(not HugeWordIsWord32Range(A));
Assert(HugeWordToInt64(A) = $1FFFFFFFE);
HugeWordAddWord32(A, $FFFFFFFF);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFD) and (HugeWordGetElement(A, 1) = 2));
Assert(HugeWordToInt64(A) = $2FFFFFFFD);
Assert(HugeWordSubtractWord32(A, $FFFFFFFF) = 1);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFE) and (HugeWordGetElement(A, 1) = 1));
Assert(HugeWordSubtractWord32(A, $FFFFFFFF) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordSubtractWord32(A, $FFFFFFFF) = 0);
Assert(HugeWordToWord32(A) = 0);
Assert(HugeWordSubtractWord32(A, $FFFFFFFF) = -1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordToHexB(A) = 'FFFFFFFF');
Assert(HugeWordSetBitScanForward(A) = 0);
Assert(HugeWordSetBitScanReverse(A) = 31);
Assert(HugeWordClearBitScanForward(A) = 32);
Assert(HugeWordClearBitScanReverse(A) = 32);
Assert(HugeWordToDouble(A) = 4294967295.0);
// $80000000
HugeWordAssignWord32(A, $80000000);
Assert(HugeWordIsWord32Range(A));
Assert(not HugeWordIsInt32Range(A));
Assert(HugeWordIsInt64Range(A));
Assert(HugeWordToWord32(A) = $80000000);
Assert(HugeWordEqualsWord32(A, $80000000));
Assert(HugeWordSetBitScanForward(A) = 31);
Assert(HugeWordSetBitScanReverse(A) = 31);
Assert(HugeWordClearBitScanForward(A) = 0);
Assert(HugeWordClearBitScanReverse(A) = 32);
// $100000000
HugeWordAssignWord32(A, $80000000);
HugeWordAdd(A, A);
Assert(HugeWordToInt64(A) = $100000000);
Assert(not HugeWordIsWord32Range(A));
Assert(HugeWordEqualsInt64(A, $100000000));
Assert(HugeWordToHexB(A) = '0000000100000000');
Assert(HugeWordSetBitScanForward(A) = 32);
Assert(HugeWordSetBitScanReverse(A) = 32);
Assert(HugeWordClearBitScanForward(A) = 0);
Assert(HugeWordClearBitScanReverse(A) = 33);
Assert(HugeWordToDouble(A) = 4294967296.0);
// $1234567890ABCDEF
HugeWordAssignInt64(A, $1234567890ABCDEF);
Assert(HugeWordToInt64(A) = $1234567890ABCDEF);
Assert(not HugeWordIsWord32Range(A));
Assert(not HugeWordIsZero(A));
Assert(HugeWordIsInt64Range(A));
Assert(HugeWordToHexB(A) = '1234567890ABCDEF');
Assert(Abs(HugeWordToDouble(A) - 1311768467294899695.0) <= 1E12);
// $7654321800000000
HugeWordAssignInt64(A, $7654321800000000);
Assert(HugeWordToInt64(A) = $7654321800000000);
Assert(not HugeWordIsZero(A));
Assert(not HugeWordIsWord32Range(A));
Assert(not HugeWordIsInt32Range(A));
Assert(HugeWordIsInt64Range(A));
Assert(HugeWordToStrB(A) = '8526495073179795456');
Assert(HugeWordToDouble(A) = 8526495073179795456.0);
Assert(HugeWordToHexB(A) = '7654321800000000');
// Swap
HugeWordAssignInt32(A, 0);
HugeWordAssignInt32(B, 1);
HugeWordSwap(A, B);
Assert(HugeWordToInt32(A) = 1);
Assert(HugeWordToInt32(B) = 0);
// Compare/Subtract
HugeWordAssignZero(A);
HugeWordAssignInt64(B, $FFFFFFFF);
Assert(HugeWordToWord32(B) = $FFFFFFFF);
Assert(HugeWordCompare(A, B) = -1);
Assert(HugeWordCompare(B, A) = 1);
Assert(HugeWordCompareWord32(B, $FFFFFFFF) = 0);
Assert(HugeWordCompareWord32(B, 0) = 1);
Assert(not HugeWordEquals(A, B));
Assert(HugeWordEquals(B, B));
HugeWordAdd(A, B);
Assert(HugeWordGetSize(A) = 1);
Assert(HugeWordGetElement(A, 0) = $FFFFFFFF);
HugeWordAdd(A, B);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFE) and (HugeWordGetElement(A, 1) = 1));
Assert(HugeWordCompare(A, B) = 1);
Assert(HugeWordCompare(B, A) = -1);
HugeWordAdd(A, B);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFD) and (HugeWordGetElement(A, 1) = 2));
Assert(HugeWordSubtract(A, B) = 1);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = $FFFFFFFE) and (HugeWordGetElement(A, 1) = 1));
Assert(HugeWordSubtract(A, B) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordSubtract(A, B) = 0);
Assert(HugeWordToWord32(A) = 0);
Assert(HugeWordSubtract(A, B) = -1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
// And/Or/Xor/Not
HugeWordAssignInt64(A, $1234678FFFFFFFF);
HugeWordAssignWord32(B, 0);
HugeWordAndHugeWord(B, A);
Assert(HugeWordToInt64(B) = 0);
HugeWordOrHugeWord(B, A);
Assert(HugeWordToInt64(B) = $1234678FFFFFFFF);
HugeWordXorHugeWord(B, A);
Assert(HugeWordToInt64(B) = 0);
HugeWordAssignInt64(A, $FFFFFFFF);
HugeWordNot(A);
Assert(HugeWordToWord32(A) = 0);
// Shl/Shr
HugeWordAssignWord32(A, $101);
HugeWordShr(A, 1);
Assert(HugeWordToWord32(A) = $80);
HugeWordShl(A, 1);
Assert(HugeWordToWord32(A) = $100);
HugeWordShl1(A);
Assert(HugeWordToWord32(A) = $200);
HugeWordShr1(A);
Assert(HugeWordToWord32(A) = $100);
// Shl1/Shl/Shr1/Shr
HugeWordAssignWord32(A, 1);
HugeWordAssignWord32(B, 1);
for I := 0 to 50 do
begin
Assert(HugeWordToInt64(A) = Int64(1) shl I);
Assert(HugeWordToInt64(B) = Int64(1) shl I);
HugeWordShl1(A);
HugeWordShl(B, 1);
end;
for I := 1 to 32 do
HugeWordShl1(A);
HugeWordShl(B, 32);
Assert(HugeWordEquals(A, B));
for I := 1 to 1000 do
HugeWordShl1(A);
HugeWordShl(B, 1000);
Assert(HugeWordEquals(A, B));
for I := 1 to 1032 do
HugeWordShr1(A);
HugeWordShr(B, 1000);
HugeWordShr(B, 32);
HugeWordNormalise(A);
HugeWordNormalise(B);
Assert(HugeWordEquals(A, B));
for I := 51 downto 1 do
begin
Assert(HugeWordToInt64(A) = Int64(1) shl I);
Assert(HugeWordToInt64(B) = Int64(1) shl I);
HugeWordShr1(A);
HugeWordShr(B, 1);
HugeWordNormalise(A);
HugeWordNormalise(B);
end;
// Shl/Shr
HugeWordAssignInt64(A, $1234678FFFFFFFF);
HugeWordShl1(A);
Assert(HugeWordToInt64(A) = $2468CF1FFFFFFFE);
HugeWordShr1(A);
Assert(HugeWordToInt64(A) = $1234678FFFFFFFF);
// Add/Subtract
HugeWordAssignZero(A);
HugeWordAddWord32(A, 1);
Assert(HugeWordToWord32(A) = 1);
Assert(HugeWordSubtractWord32(A, 1) = 0);
Assert(HugeWordToWord32(A) = 0);
Assert(HugeWordSubtractWord32(A, 1) = -1);
Assert(HugeWordToWord32(A) = 1);
// Add/Subtract
HugeWordAssignZero(A);
HugeWordAssignWord32(B, 1);
HugeWordAdd(A, B);
Assert(HugeWordToWord32(A) = 1);
Assert(HugeWordSubtract(A, B) = 0);
Assert(HugeWordToWord32(A) = 0);
Assert(HugeWordSubtract(A, B) = -1);
Assert(HugeWordToWord32(A) = 1);
// Add/Subtract
HugeWordAssignInt64(A, $FFFFFFFF);
HugeWordAddWord32(A, 1);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = 0) and (HugeWordGetElement(A, 1) = 1));
Assert(HugeWordSubtractWord32(A, 1) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordSubtractWord32(A, 1) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFE);
// Add/Subtract
HugeWordAssignInt64(A, $FFFFFFFF);
HugeWordAssignWord32(B, 1);
HugeWordAdd(A, B);
Assert(HugeWordGetSize(A) = 2);
Assert((HugeWordGetElement(A, 0) = 0) and (HugeWordGetElement(A, 1) = 1));
Assert(HugeWordSubtract(A, B) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFF);
Assert(HugeWordSubtract(A, B) = 1);
Assert(HugeWordToWord32(A) = $FFFFFFFE);
// Add/Subtract
StrToHugeWordB('111111111111111111111111111111111111111111111111111111111', A);
StrToHugeWordB('222222222222222222222222222222222222222222222222222222222', B);
HugeWordAdd(A, B);
Assert(HugeWordToStrB(A) = '333333333333333333333333333333333333333333333333333333333');
HugeWordSubtract(A, B);
Assert(HugeWordToStrB(A) = '111111111111111111111111111111111111111111111111111111111');
HugeWordSubtract(A, A);
Assert(HugeWordIsZero(A));
// Multiply/Divide
HugeWordAssignWord32(A, $10000000);
HugeWordAssignWord32(B, $20000000);
HugeWordMultiply(C, A, B);
Assert(HugeWordToInt64(C) = $200000000000000);
HugeWordDivide(C, B, D, C);
Assert(HugeWordToInt64(D) = $10000000);
Assert(HugeWordIsZero(C));
// Multiply/Divide
StrToHugeWordB('111111111111111111111111111111111111', A);
StrToHugeWordB('100000000000000000000000000000000000', B);
HugeWordMultiply(C, A, B);
Assert(HugeWordToStrB(A) = '111111111111111111111111111111111111');
Assert(HugeWordToStrB(C) = '11111111111111111111111111111111111100000000000000000000000000000000000');
HugeWordDivide(C, B, D, C);
Assert(HugeWordToStrB(D) = '111111111111111111111111111111111111');
Assert(HugeWordToStrB(C) = '0');
HugeWordMultiplyWord8(D, 10);
Assert(HugeWordToStrB(D) = '1111111111111111111111111111111111110');
HugeWordMultiplyWord16(D, 100);
Assert(HugeWordToStrB(D) = '111111111111111111111111111111111111000');
HugeWordMultiplyWord32(D, 1000);
Assert(HugeWordToStrB(D) = '111111111111111111111111111111111111000000');
HugeWordDivideWord32(D, 1000000, D, F);
Assert(HugeWordToStrB(D) = '111111111111111111111111111111111111');
Assert(F = 0);
StrToHugeWordB('1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', A);
StrToHugeWordB('1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', B);
HugeWordMultiply(C, A, B);
Assert(HugeWordToStrB(C) = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
// Multiply_ShiftAdd
StrToHugeWordB('111111111111111111111111111111111111', A);
StrToHugeWordB('100000000000000000000000000000000000', B);
HugeWordMultiply_ShiftAdd(C, A, B);
Assert(HugeWordToStrB(C) = '11111111111111111111111111111111111100000000000000000000000000000000000');
StrToHugeWordB('1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', A);
StrToHugeWordB('1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', B);
HugeWordMultiply_ShiftAdd(C, A, B);
Assert(HugeWordToStrB(C) = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
// Multiply_Karatsuba
StrToHugeWordB('111111111111111111111111111111111111', A);
StrToHugeWordB('100000000000000000000000000000000000', B);
HugeWordMultiply_Karatsuba(C, A, B);
Assert(HugeWordToStrB(C) = '11111111111111111111111111111111111100000000000000000000000000000000000');
StrToHugeWordB('1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', A);
StrToHugeWordB('1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', B);
HugeWordMultiply_Karatsuba(C, A, B);
Assert(HugeWordToStrB(C) = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
// ISqrt/Sqr
HugeWordAssignWord32(A, $FFFF);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $FF);
HugeWordAssignWord32(A, $10000);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $100);
HugeWordAssignInt64(A, $FFFFFFFF);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $FFFF);
HugeWordAssignInt64(A, $100000000);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $10000);
HugeWordAssignInt64(A, $10000FFFF);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $10000);
StrToHugeWordB('10000000000000000000000000000000000000000', A);
HugeWordISqrt(A);
Assert(HugeWordToStrB(A) = '100000000000000000000');
HugeWordSqr(A, A);
Assert(HugeWordToStrB(A) = '10000000000000000000000000000000000000000');
HugeWordAssignWord32(A, $10000000);
HugeWordSqr(A, A);
Assert(HugeWordToInt64(A) = $100000000000000);
HugeWordISqrt(A);
Assert(HugeWordToInt64(A) = $10000000);
// GCD
HugeWordAssignWord32(A, 111);
HugeWordAssignWord32(B, 159);
HugeWordGCD(A, B, C);
Assert(HugeWordToStrB(C) = '3');
// GCD
StrToHugeWordB('359334085968622831041960188598043661065388726959079837', A); // Bell number prime
StrToHugeWordB('1298074214633706835075030044377087', B); // Carol prime
HugeWordGCD(A, B, C);
Assert(HugeWordToStrB(C) = '1');
// PowerAndMod
HugeWordAssignWord32(A, 3);
HugeWordAssignWord32(B, 500);
HugeWordAssignWord32(C, 5);
HugeWordPowerAndMod(D, A, B, C);
Assert(HugeWordToStrB(D) = '1');
// PowerAndMod
HugeWordAssignWord32(A, 3);
HugeWordAssignWord32(B, 123456);
HugeWordAssignWord32(C, 7);
HugeWordPowerAndMod(D, A, B, C);
Assert(HugeWordToStrB(D) = '1');
// PowerAndMod
HugeWordAssignWord32(A, 2905);
HugeWordAssignWord32(B, 323);
HugeWordAssignWord32(C, 245363);
HugeWordPowerAndMod(D, A, B, C);
Assert(HugeWordToStrB(D) = '13388');
// PowerAndMod
StrToHugeWordB('9999999999', A);
HugeWordAssignWord32(B, 10);
HugeWordPower(B, 100);
HugeWordAssignWord32(C, 700);
HugeWordPowerAndMod(D, A, B, C);
Assert(HugeWordToStrB(D) = '501');
// Power/Mod
HugeWordAssignWord32(A, 3);
HugeWordAssignWord32(C, 5);
HugeWordPower(A, 500);
Assert(HugeWordToStrB(A) =
'36360291795869936842385267079543319118023385026001623040346035832580600191583895' +
'48419850826297938878330817970253440385575285593151701306614299243091656202578002' +
'1771247847643450125342836565813209972590371590152578728008385990139795377610001');
HugeWordMod(A, C, D);
Assert(HugeWordToStrB(D) = '1');
// Power/Mod
HugeWordAssignWord32(A, 3);
HugeWordAssignWord32(C, 7);
HugeWordPower(A, 123456);
HugeWordMod(A, C, D);
Assert(HugeWordToStrB(D) = '1');
// Power
HugeWordAssignZero(A);
HugeWordPower(A, 0);
Assert(HugeWordToInt32(A) = 1);
HugeWordAssignZero(A);
HugeWordPower(A, 1);
Assert(HugeWordToInt32(A) = 0);
HugeWordAssignOne(A);
HugeWordPower(A, 0);
Assert(HugeWordToInt32(A) = 1);
HugeWordAssignOne(A);
HugeWordPower(A, 1);
Assert(HugeWordToInt32(A) = 1);
// AssignDouble
HugeWordAssignDouble(A, 0.0);
Assert(HugeWordToInt64(A) = 0);
HugeWordAssignDouble(A, 1.0);
Assert(HugeWordToInt64(A) = 1);
HugeWordAssignDouble(A, 4294967295.0);
Assert(HugeWordToInt64(A) = $FFFFFFFF);
HugeWordAssignDouble(A, 4294967296.0);
Assert(HugeWordToInt64(A) = $100000000);
// HexTo/ToHex
HexToHugeWordB('0', A);
Assert(HugeWordToHexB(A) = '00000000');
StrToHugeWordB('123456789', A);
Assert(HugeWordToHexB(A) = '075BCD15');
HexToHugeWordB('123456789ABCDEF', A);
Assert(HugeWordToHexB(A) = '0123456789ABCDEF');
Assert(HugeWordToStrB(A) = '81985529216486895');
HexToHugeWordB('0123456789ABCDEF00112233F', A);
Assert(HugeWordToHexB(A) = '00000000123456789ABCDEF00112233F');
// StrTo/ToStr
StrToHugeWordB('12345', A);
Assert(HugeWordToWord32(A) = 12345);
Assert(HugeWordToStrB(A) = '12345');
// StrTo/ToStr
S := '123456789012345678901234567890123456789012345678901234567890';
StrToHugeWordB(S, A);
for I := 1 to 100 do
begin
HugeWordMultiplyWord8(A, 10);
S := S + '0';
Assert(HugeWordToStrB(A) = S);
StrToHugeWordB(S, B);
Assert(HugeWordEquals(A, B));
end;
// Prime
HugeWordAssignWord32(A, 1);
Assert(HugeWordIsPrime(A) = pNotPrime);
HugeWordAssignWord32(A, 31);
Assert(HugeWordIsPrime(A) = pPrime);
HugeWordAssignWord32(A, 982451653);
Assert(HugeWordIsPrime(A) <> pNotPrime);
HugeWordAssignWord32(A, 3464946713);
Assert(HugeWordIsPrime(A) <> pNotPrime);
HugeWordAssignWord32(A, 3464946767);
Assert(HugeWordIsPrime(A) = pNotPrime);
HugeWordAssignWord32(A, 3464946769);
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('359334085968622831041960188598043661065388726959079837', A); // Bell number prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('1298074214633706835075030044377087', A); // Carol prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('393050634124102232869567034555427371542904833', A); // Cullen prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('8683317618811886495518194401279999999', A); // Factorial prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('19134702400093278081449423917', A); // Fibonacci prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('1363005552434666078217421284621279933627102780881053358473', A); // Padovan prime
Assert(HugeWordIsPrime(A) <> pNotPrime);
StrToHugeWordB('1363005552434666078217421284621279933627102780881053358473', A); // Padovan prime
HugeWordNextPotentialPrime(A);
Assert(HugeWordToStrB(A) = '1363005552434666078217421284621279933627102780881053358551');
HugeWordAssignWord32(A, 340561); // Carmichael number 340561 = 13 * 17 * 23 * 67
Assert(HugeWordIsPrime(A) = pNotPrime);
HugeWordAssignWord32(A, 82929001); // Carmichael number 82929001 = 281 * 421 * 701
Assert(HugeWordIsPrime(A) = pNotPrime);
StrToHugeWordB('975177403201', A); // Carmichael number 975177403201 = 2341 * 2861 * 145601
Assert(HugeWordIsPrime(A) = pNotPrime);
StrToHugeWordB('989051977369', A); // Carmichael number 989051977369 = 173 * 36809 * 155317
Assert(HugeWordIsPrime(A) = pNotPrime);
StrToHugeWordB('999629786233', A); // Carmichael number 999629786233 = 13 * 43 * 127 * 1693 * 8317
Assert(HugeWordIsPrime(A) = pNotPrime);
// ExtendedEuclid
HugeWordAssignWord32(A, 120);
HugeWordAssignWord32(B, 23);
HugeWordExtendedEuclid(A, B, C, X, Y);
Assert(HugeWordToWord32(C) = 1);
Assert(HugeIntToInt32(X) = -9);
Assert(HugeIntToInt32(Y) = 47);
// ExtendedEuclid
HugeWordAssignWord32(A, 11391);
HugeWordAssignWord32(B, 5673);
HugeWordExtendedEuclid(A, B, C, X, Y);
Assert(HugeWordToWord32(C) = 3);
Assert(HugeIntToInt32(X) = -126);
Assert(HugeIntToInt32(Y) = 253);
// ModInv
HugeWordAssignWord32(A, 3);
HugeWordAssignWord32(B, 26);
Assert(HugeWordModInv(A, B, C));
Assert(HugeWordToWord32(C) = 9);
// ModInv
HugeWordAssignWord32(A, 6);
HugeWordAssignWord32(B, 3);
Assert(not HugeWordModInv(A, B, C));
// ModInv
HugeWordAssignWord32(A, 31);
HugeWordAssignWord32(B, 8887231);
Assert(HugeWordModInv(A, B, C));
Assert(HugeWordToWord32(C) = 2293479);
// ModInv
HugeWordAssignWord32(A, 999961543);
StrToHugeWordB('3464946713311', B);
Assert(HugeWordModInv(A, B, C));
Assert(HugeWordToStrB(C) = '2733464305244');
HugeIntFinalise(Y);
HugeIntFinalise(X);
HugeWordFinalise(D);
HugeWordFinalise(C);
HugeWordFinalise(B);
HugeWordFinalise(A);
end;
procedure Test_HugeInt;
var A, B, C, D : HugeInt;
F : HugeWord;
K : Word32;
L : Int32;
begin
HugeIntInit(A);
HugeIntInit(B);
HugeIntInit(C);
HugeIntInit(D);
HugeWordInit(F);
// Zero
HugeIntAssignZero(A);
Assert(HugeIntIsZero(A));
Assert(HugeIntIsPositiveOrZero(A));
Assert(HugeIntIsNegativeOrZero(A));
Assert(not HugeIntIsPositive(A));
Assert(not HugeIntIsNegative(A));
Assert(HugeIntIsInt32Range(A));
Assert(HugeIntIsWord32Range(A));
Assert(HugeIntToStrB(A) = '0');
Assert(HugeIntToHexB(A) = '00000000');
Assert(HugeIntToWord32(A) = 0);
Assert(HugeIntToInt32(A) = 0);
Assert(HugeIntToDouble(A) = 0.0);
StrToHugeIntB('0', A);
Assert(HugeIntIsZero(A));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(HugeIntCompareInt64(A, $7FFFFFFFFFFFFFFF) = -1);
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
HugeIntAddInt32(A, 0);
Assert(HugeIntIsZero(A));
HugeIntSubtractInt32(A, 0);
Assert(HugeIntIsZero(A));
HugeIntMultiplyInt8(A, 0);
Assert(HugeIntIsZero(A));
HugeIntMultiplyInt8(A, 1);
Assert(HugeIntIsZero(A));
HugeIntMultiplyInt8(A, -1);
Assert(HugeIntIsZero(A));
HugeIntMultiplyWord8(A, 0);
Assert(HugeIntIsZero(A));
HugeIntMultiplyWord8(A, 1);
Assert(HugeIntIsZero(A));
HugeIntMultiplyHugeWord(A, F);
Assert(HugeIntIsZero(A));
HugeIntMultiplyHugeInt(A, A);
Assert(HugeIntIsZero(A));
HugeIntSqr(A);
Assert(HugeIntIsZero(A));
HugeIntISqrt(A);
Assert(HugeIntIsZero(A));
// One
HugeIntAssignOne(A);
Assert(not HugeIntIsZero(A));
Assert(HugeIntIsPositiveOrZero(A));
Assert(not HugeIntIsNegativeOrZero(A));
Assert(HugeIntIsOne(A));
Assert(not HugeIntIsMinusOne(A));
Assert(HugeIntToStrB(A) = '1');
Assert(HugeIntToHexB(A) = '00000001');
Assert(HugeIntIsPositive(A));
Assert(not HugeIntIsNegative(A));
Assert(HugeIntIsInt32Range(A));
Assert(HugeIntIsWord32Range(A));
Assert(HugeIntToDouble(A) = 1.0);
StrToHugeIntB('1', A);
Assert(HugeIntIsOne(A));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(HugeIntCompareInt64(A, $7FFFFFFFFFFFFFFF) = -1);
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
HugeIntAddInt32(A, 0);
Assert(HugeIntIsOne(A));
HugeIntSubtractInt32(A, 0);
Assert(HugeIntIsOne(A));
HugeIntMultiplyInt8(A, 1);
Assert(HugeIntIsOne(A));
HugeIntMultiplyInt8(A, -1);
Assert(HugeIntIsMinusOne(A));
HugeIntMultiplyInt8(A, -1);
Assert(HugeIntIsOne(A));
HugeIntMultiplyWord8(A, 1);
Assert(HugeIntIsOne(A));
HugeIntSqr(A);
Assert(HugeIntIsOne(A));
HugeIntISqrt(A);
Assert(HugeIntIsOne(A));
// MinusOne
HugeIntAssignMinusOne(A);
Assert(not HugeIntIsZero(A));
Assert(not HugeIntIsPositiveOrZero(A));
Assert(HugeIntIsNegativeOrZero(A));
Assert(not HugeIntIsOne(A));
Assert(HugeIntIsMinusOne(A));
Assert(HugeIntToStrB(A) = '-1');
Assert(HugeIntToHexB(A) = '-00000001');
Assert(not HugeIntIsPositive(A));
Assert(HugeIntIsNegative(A));
Assert(HugeIntIsInt32Range(A));
Assert(HugeIntIsInt64Range(A));
Assert(not HugeIntIsWord32Range(A));
Assert(HugeIntToDouble(A) = -1.0);
StrToHugeIntB('-1', A);
Assert(HugeIntIsMinusOne(A));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(HugeIntCompareInt64(A, $7FFFFFFFFFFFFFFF) = -1);
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
HugeIntMultiplyInt8(A, 1);
Assert(HugeIntIsMinusOne(A));
HugeIntAddWord32(A, 1);
Assert(HugeIntIsZero(A));
HugeIntAddInt32(A, -1);
Assert(HugeIntIsMinusOne(A));
HugeIntAddInt32(A, 0);
Assert(HugeIntIsMinusOne(A));
HugeIntSubtractInt32(A, 0);
Assert(HugeIntIsMinusOne(A));
HugeWordAssignHugeIntAbs(F, A);
Assert(HugeWordIsOne(F));
// MinInt64 (-$8000000000000000)
HugeIntAssignInt64(A, MinInt64 { -$8000000000000000 });
Assert(HugeIntToInt64(A) = MinInt64 { -$8000000000000000 });
Assert(HugeIntToStrB(A) = '-9223372036854775808');
Assert(HugeIntToHexB(A) = '-8000000000000000');
Assert(HugeIntToDouble(A) = -9223372036854775808.0);
Assert(HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(not HugeIntEqualsInt64(A, MinInt32 { -$80000000 }));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 0);
Assert(HugeIntCompareInt64(A, -$7FFFFFFFFFFFFFFF) = -1);
Assert(not HugeIntIsInt32Range(A));
Assert(HugeIntIsInt64Range(A));
StrToHugeIntB('-9223372036854775808', A);
Assert(HugeIntToStrB(A) = '-9223372036854775808');
HugeIntAbsInPlace(A);
Assert(HugeIntToStrB(A) = '9223372036854775808');
Assert(HugeIntToHexB(A) = '8000000000000000');
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(not HugeIntIsInt64Range(A));
HugeIntNegate(A);
Assert(HugeIntToInt64(A) = MinInt64 { -$8000000000000000 });
// MinInt64 + 1 (-$7FFFFFFFFFFFFFFF)
HugeIntAssignInt64(A, -$7FFFFFFFFFFFFFFF);
Assert(HugeIntToInt64(A) = -$7FFFFFFFFFFFFFFF);
Assert(HugeIntToStrB(A) = '-9223372036854775807');
Assert(HugeIntToHexB(A) = '-7FFFFFFFFFFFFFFF');
{$IFNDEF DELPHIXE2_UP}
{$IFNDEF FREEPASCAL}
{$IFNDEF CPU_32}
Assert(HugeIntToDouble(A) = Double(-9223372036854775807.0));
{$ENDIF}
{$ENDIF}
{$ENDIF}
Assert(HugeIntEqualsInt64(A, -$7FFFFFFFFFFFFFFF));
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(HugeIntCompareInt64(A, -$7FFFFFFFFFFFFFFE) = -1);
Assert(HugeIntCompareInt64(A, -$7FFFFFFFFFFFFFFF) = 0);
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(HugeIntIsInt64Range(A));
HugeIntAbsInPlace(A);
Assert(HugeIntToStrB(A) = '9223372036854775807');
Assert(HugeIntToHexB(A) = '7FFFFFFFFFFFFFFF');
Assert(HugeIntToInt64(A) = $7FFFFFFFFFFFFFFF);
Assert(HugeIntEqualsInt64(A, $7FFFFFFFFFFFFFFF));
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
Assert(HugeIntIsInt64Range(A));
HugeIntNegate(A);
Assert(HugeIntToInt64(A) = -$7FFFFFFFFFFFFFFF);
// MinInt64 - 1 (-$8000000000000001)
HugeIntAssignInt64(A, MinInt64 { -$8000000000000000 });
HugeIntSubtractInt32(A, 1);
Assert(HugeIntToStrB(A) = '-9223372036854775809');
Assert(HugeIntToHexB(A) = '-8000000000000001');
{$IFNDEF DELPHIXE2_UP}
{$IFNDEF FREEPASCAL}
{$IFNDEF CPU_32}
Assert(HugeIntToDouble(A) = Double(-9223372036854775809.0));
{$ENDIF}
{$ENDIF}
{$ENDIF}
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = -1);
Assert(not HugeIntIsInt64Range(A));
HugeIntAbsInPlace(A);
Assert(HugeIntToStrB(A) = '9223372036854775809');
Assert(not HugeIntEqualsInt64(A, MinInt64 { -$8000000000000000 }));
Assert(HugeIntCompareInt64(A, MinInt64 { -$8000000000000000 }) = 1);
HugeIntNegate(A);
Assert(HugeIntToStrB(A) = '-9223372036854775809');
// Equals/Compare
HugeIntAssignInt32(A, -1);
HugeIntAssignWord32(B, 2);
HugeIntAssignZero(C);
Assert(HugeIntEqualsInt32(A, -1));
Assert(not HugeIntEqualsInt32(A, 1));
Assert(HugeIntEqualsWord32(B, 2));
Assert(HugeIntEqualsInt32(B, 2));
Assert(not HugeIntEqualsInt32(B, -2));
Assert(HugeIntEqualsInt32(C, 0));
Assert(HugeIntEqualsWord32(C, 0));
Assert(not HugeIntEqualsWord32(C, 1));
Assert(HugeIntEqualsInt64(C, 0));
Assert(not HugeIntEqualsInt64(A, 1));
Assert(HugeIntCompareWord32(A, 0) = -1);
Assert(HugeIntCompareWord32(A, 1) = -1);
Assert(HugeIntCompareWord32(B, 1) = 1);
Assert(HugeIntCompareWord32(B, 2) = 0);
Assert(HugeIntCompareWord32(C, 0) = 0);
Assert(HugeIntCompareWord32(C, 1) = -1);
Assert(HugeIntCompareInt32(A, 0) = -1);
Assert(HugeIntCompareInt32(A, -1) = 0);
Assert(HugeIntCompareInt32(A, -2) = 1);
Assert(HugeIntCompareInt32(C, -1) = 1);
Assert(HugeIntCompareInt32(C, 0) = 0);
Assert(HugeIntCompareInt32(C, 1) = -1);
Assert(HugeIntCompareInt64(A, 0) = -1);
Assert(HugeIntCompareInt64(A, -1) = 0);
Assert(HugeIntCompareInt64(A, -2) = 1);
Assert(HugeIntCompareInt64(C, 0) = 0);
Assert(HugeIntCompareInt64(C, 1) = -1);
Assert(not HugeIntEqualsHugeInt(A, B));
Assert(not HugeIntEqualsHugeInt(B, C));
Assert(HugeIntEqualsHugeInt(A, A));
Assert(HugeIntEqualsHugeInt(B, B));
Assert(HugeIntEqualsHugeInt(C, C));
Assert(HugeIntCompareHugeInt(A, B) = -1);
Assert(HugeIntCompareHugeInt(B, A) = 1);
Assert(HugeIntCompareHugeInt(A, A) = 0);
Assert(HugeIntCompareHugeInt(B, B) = 0);
Assert(HugeIntCompareHugeInt(C, A) = 1);
Assert(HugeIntCompareHugeInt(C, B) = -1);
Assert(HugeIntCompareHugeInt(C, C) = 0);
Assert(HugeIntCompareHugeInt(A, C) = -1);
Assert(HugeIntCompareHugeInt(B, C) = 1);
Assert(HugeIntCompareHugeIntAbs(A, B) = -1);
Assert(HugeIntCompareHugeIntAbs(B, A) = 1);
Assert(HugeIntCompareHugeIntAbs(A, C) = 1);
Assert(HugeIntCompareHugeIntAbs(B, C) = 1);
Assert(HugeIntCompareHugeIntAbs(C, A) = -1);
Assert(HugeIntCompareHugeIntAbs(C, B) = -1);
Assert(HugeIntCompareHugeIntAbs(A, A) = 0);
Assert(HugeIntCompareHugeIntAbs(B, B) = 0);
Assert(HugeIntCompareHugeIntAbs(C, C) = 0);
// Min/Max
HugeIntAssignInt32(A, -1);
HugeIntAssignInt32(B, 0);
HugeIntAssignInt32(C, 1);
HugeIntMin(A, B);
Assert(HugeIntToInt32(A) = -1);
HugeIntMin(B, A);
Assert(HugeIntToInt32(B) = -1);
HugeIntMax(C, A);
Assert(HugeIntToInt32(C) = 1);
HugeIntMax(A, C);
Assert(HugeIntToInt32(A) = 1);
// Swap
HugeIntAssignInt32(A, 0);
HugeIntAssignInt32(B, 1);
HugeIntSwap(A, B);
Assert(HugeIntToInt32(A) = 1);
Assert(HugeIntToInt32(B) = 0);
// Add/Subtract
HugeIntAssignInt32(A, 0);
HugeIntAssignInt32(B, 1);
HugeIntAssignInt32(C, -1);
HugeIntAddHugeInt(A, B);
Assert(HugeIntToInt32(A) = 1);
HugeIntAddHugeInt(A, B);
Assert(HugeIntToInt32(A) = 2);
HugeIntAddHugeInt(A, C);
Assert(HugeIntToInt32(A) = 1);
HugeIntAddHugeInt(A, C);
Assert(HugeIntToInt32(A) = 0);
HugeIntAddHugeInt(A, C);
Assert(HugeIntToInt32(A) = -1);
HugeIntAddHugeInt(A, C);
Assert(HugeIntToInt32(A) = -2);
HugeIntAddHugeInt(A, B);
Assert(HugeIntToInt32(A) = -1);
HugeIntAddHugeInt(A, B);
Assert(HugeIntToInt32(A) = 0);
HugeIntAddHugeInt(A, B);
Assert(HugeIntToInt32(A) = 1);
HugeIntSubtractHugeInt(A, B);
Assert(HugeIntToInt32(A) = 0);
HugeIntSubtractHugeInt(A, B);
Assert(HugeIntToInt32(A) = -1);
HugeIntSubtractHugeInt(A, B);
Assert(HugeIntToInt32(A) = -2);
HugeIntSubtractHugeInt(A, C);
Assert(HugeIntToInt32(A) = -1);
HugeIntSubtractHugeInt(A, C);
Assert(HugeIntToInt32(A) = 0);
HugeIntSubtractHugeInt(A, C);
Assert(HugeIntToInt32(A) = 1);
HugeIntSubtractHugeInt(A, C);
Assert(HugeIntToInt32(A) = 2);
// Add/Subtract
HugeIntAssignInt32(A, 0);
HugeIntAddInt32(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntAddInt32(A, -1);
Assert(HugeIntToInt32(A) = 0);
HugeIntAddInt32(A, -1);
Assert(HugeIntToInt32(A) = -1);
HugeIntAddInt32(A, -1);
Assert(HugeIntToInt32(A) = -2);
HugeIntAddInt32(A, 1);
Assert(HugeIntToInt32(A) = -1);
HugeIntAddInt32(A, 1);
Assert(HugeIntToInt32(A) = 0);
HugeIntAddInt32(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntAddInt32(A, 1);
Assert(HugeIntToInt32(A) = 2);
HugeIntSubtractInt32(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntSubtractInt32(A, 1);
Assert(HugeIntToInt32(A) = 0);
HugeIntSubtractInt32(A, 1);
Assert(HugeIntToInt32(A) = -1);
HugeIntSubtractInt32(A, 1);
Assert(HugeIntToInt32(A) = -2);
HugeIntSubtractInt32(A, -1);
Assert(HugeIntToInt32(A) = -1);
HugeIntSubtractInt32(A, -1);
Assert(HugeIntToInt32(A) = 0);
HugeIntSubtractInt32(A, -1);
Assert(HugeIntToInt32(A) = 1);
HugeIntSubtractInt32(A, -1);
Assert(HugeIntToInt32(A) = 2);
// Add/Subtract
HugeIntAssignInt32(A, -1);
HugeIntAddWord32(A, 1);
Assert(HugeIntToInt32(A) = 0);
HugeIntAddWord32(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntAddWord32(A, 1);
Assert(HugeIntToInt32(A) = 2);
HugeIntSubtractWord32(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntSubtractWord32(A, 1);
Assert(HugeIntToInt32(A) = 0);
HugeIntSubtractWord32(A, 1);
Assert(HugeIntToInt32(A) = -1);
HugeIntSubtractWord32(A, 1);
Assert(HugeIntToInt32(A) = -2);
// Multiply
HugeIntAssignInt32(A, 10);
HugeIntMultiplyWord8(A, 10);
Assert(HugeIntToInt32(A) = 100);
HugeIntMultiplyWord16(A, 10);
Assert(HugeIntToInt32(A) = 1000);
HugeIntMultiplyWord32(A, 10);
Assert(HugeIntToInt32(A) = 10000);
HugeIntAssignInt32(A, -10);
HugeIntMultiplyWord8(A, 10);
Assert(HugeIntToInt32(A) = -100);
HugeIntMultiplyWord16(A, 10);
Assert(HugeIntToInt32(A) = -1000);
HugeIntMultiplyWord32(A, 10);
Assert(HugeIntToInt32(A) = -10000);
// Multiply
HugeIntAssignInt32(A, -10);
HugeIntMultiplyInt8(A, -10);
Assert(HugeIntToInt32(A) = 100);
HugeIntMultiplyInt8(A, 10);
Assert(HugeIntToInt32(A) = 1000);
HugeIntMultiplyInt8(A, -10);
Assert(HugeIntToInt32(A) = -10000);
HugeIntMultiplyInt8(A, 10);
Assert(HugeIntToInt32(A) = -100000);
HugeIntMultiplyInt8(A, 0);
Assert(HugeIntToInt32(A) = 0);
// Multiply
HugeIntAssignInt32(A, -10);
HugeIntMultiplyInt16(A, -10);
Assert(HugeIntToInt32(A) = 100);
HugeIntMultiplyInt16(A, 10);
Assert(HugeIntToInt32(A) = 1000);
HugeIntMultiplyInt16(A, -10);
Assert(HugeIntToInt32(A) = -10000);
HugeIntMultiplyInt16(A, 10);
Assert(HugeIntToInt32(A) = -100000);
HugeIntMultiplyInt16(A, 0);
Assert(HugeIntToInt32(A) = 0);
// Multiply
HugeIntAssignInt32(A, -10);
HugeIntMultiplyInt32(A, -10);
Assert(HugeIntToInt32(A) = 100);
HugeIntMultiplyInt32(A, 10);
Assert(HugeIntToInt32(A) = 1000);
HugeIntMultiplyInt32(A, -10);
Assert(HugeIntToInt32(A) = -10000);
HugeIntMultiplyInt32(A, 10);
Assert(HugeIntToInt32(A) = -100000);
HugeIntMultiplyInt32(A, 0);
Assert(HugeIntToInt32(A) = 0);
// Multiply
HugeIntAssignInt32(A, 10);
HugeIntAssignInt32(B, 10);
HugeIntAssignInt32(C, -10);
HugeIntMultiplyHugeInt(A, B);
Assert(HugeIntToInt32(A) = 100);
HugeIntMultiplyHugeInt(A, C);
Assert(HugeIntToInt32(A) = -1000);
HugeIntMultiplyHugeInt(A, B);
Assert(HugeIntToInt32(A) = -10000);
HugeIntMultiplyHugeInt(A, C);
Assert(HugeIntToInt32(A) = 100000);
HugeIntAssignInt32(B, 1);
HugeIntMultiplyHugeInt(A, B);
Assert(HugeIntToInt32(A) = 100000);
HugeIntAssignInt32(B, -1);
HugeIntMultiplyHugeInt(A, B);
Assert(HugeIntToInt32(A) = -100000);
HugeIntAssignInt32(B, 0);
HugeIntMultiplyHugeInt(A, B);
Assert(HugeIntToInt32(A) = 0);
// Multiply
HugeIntAssignInt32(A, 10);
HugeWordAssignWord32(F, 10);
HugeIntMultiplyHugeWord(A, F);
Assert(HugeIntToInt32(A) = 100);
HugeIntAssignInt32(A, -10);
HugeIntMultiplyHugeWord(A, F);
Assert(HugeIntToInt32(A) = -100);
// Sqr
HugeIntAssignInt32(A, -17);
HugeIntSqr(A);
Assert(HugeIntToInt32(A) = 289);
// ISqrt
HugeIntAssignInt32(A, 289);
HugeIntISqrt(A);
Assert(HugeIntToInt32(A) = 17);
// Divide
HugeIntAssignInt32(A, -1000);
HugeIntDivideWord32(A, 3, B, K);
Assert(HugeIntToInt32(B) = -333);
Assert(K = 1);
// Divide
HugeIntAssignInt32(A, -1000);
HugeIntDivideInt32(A, 3, B, L);
Assert(HugeIntToInt32(B) = -333);
Assert(L = 1);
HugeIntDivideInt32(A, -3, B, L);
Assert(HugeIntToInt32(B) = 333);
Assert(L = 1);
HugeIntAssignInt32(A, 1000);
HugeIntDivideInt32(A, 3, B, L);
Assert(HugeIntToInt32(B) = 333);
Assert(L = 1);
HugeIntDivideInt32(A, -3, B, L);
Assert(HugeIntToInt32(B) = -333);
Assert(L = 1);
// Divide
HugeIntAssignInt32(A, -1000);
HugeIntAssignInt32(B, 3);
HugeIntDivideHugeInt(A, B, C, D);
Assert(HugeIntToInt32(C) = -333);
Assert(HugeIntToInt32(D) = 1);
HugeIntAssignInt32(B, -3);
HugeIntDivideHugeInt(A, B, C, D);
Assert(HugeIntToInt32(C) = 333);
Assert(HugeIntToInt32(D) = 1);
HugeIntAssignInt32(A, 1000);
HugeIntAssignInt32(B, 3);
HugeIntDivideHugeInt(A, B, C, D);
Assert(HugeIntToInt32(C) = 333);
Assert(HugeIntToInt32(D) = 1);
HugeIntAssignInt32(B, -3);
HugeIntDivideHugeInt(A, B, C, D);
Assert(HugeIntToInt32(C) = -333);
Assert(HugeIntToInt32(D) = 1);
// Mod
HugeIntAssignInt32(A, -1000);
HugeIntAssignInt32(B, 3);
HugeIntMod(A, B, C);
Assert(HugeIntToInt32(C) = 1);
// Power
HugeIntAssignInt32(A, -2);
HugeIntPower(A, 0);
Assert(HugeIntToInt32(A) = 1);
HugeIntAssignInt32(A, -2);
HugeIntPower(A, 1);
Assert(HugeIntToInt32(A) = -2);
HugeIntAssignInt32(A, -2);
HugeIntPower(A, 2);
Assert(HugeIntToInt32(A) = 4);
HugeIntAssignInt32(A, -2);
HugeIntPower(A, 3);
Assert(HugeIntToInt32(A) = -8);
HugeIntAssignInt32(A, -2);
HugeIntPower(A, 4);
Assert(HugeIntToInt32(A) = 16);
// Power
HugeIntAssignZero(A);
HugeIntPower(A, 0);
Assert(HugeIntToInt32(A) = 1);
HugeIntAssignZero(A);
HugeIntPower(A, 1);
Assert(HugeIntToInt32(A) = 0);
HugeIntAssignOne(A);
HugeIntPower(A, 0);
Assert(HugeIntToInt32(A) = 1);
HugeIntAssignOne(A);
HugeIntPower(A, 1);
Assert(HugeIntToInt32(A) = 1);
HugeIntAssignMinusOne(A);
HugeIntPower(A, 0);
Assert(HugeIntToInt32(A) = 1);
HugeIntAssignMinusOne(A);
HugeIntPower(A, 1);
Assert(HugeIntToInt32(A) = -1);
HugeIntAssignMinusOne(A);
HugeIntPower(A, 2);
Assert(HugeIntToInt32(A) = 1);
// AssignDouble
HugeIntAssignDouble(A, 0.0);
Assert(HugeIntToDouble(A) = 0.0);
HugeIntAssignDouble(A, 1.0);
Assert(HugeIntToDouble(A) = 1.0);
HugeIntAssignDouble(A, -1.0);
Assert(HugeIntToDouble(A) = -1.0);
// ToStr/StrTo
StrToHugeIntB('-1234567890', A);
Assert(HugeIntToInt32(A) = -1234567890);
Assert(HugeIntToStrB(A) = '-1234567890');
Assert(HugeIntToHexB(A) = '-499602D2');
StrToHugeIntB('123456789012345678901234567890123456789012345678901234567890', A);
Assert(HugeIntToStrB(A) = '123456789012345678901234567890123456789012345678901234567890');
// ToHex/HexTo
HexToHugeIntB('-0123456789ABCDEF', A);
Assert(HugeIntToHexB(A) = '-0123456789ABCDEF');
HexToHugeIntB('-F1230', A);
Assert(HugeIntToHexB(A) = '-000F1230');
HugeWordFinalise(F);
HugeIntFinalise(D);
HugeIntFinalise(C);
HugeIntFinalise(B);
HugeIntFinalise(A);
end;
procedure Test;
begin
Assert(HugeWordElementBits = 32);
Test_HugeWord;
Test_HugeInt;
end;
{$ENDIF}
{$IFDEF HUGEINT_PROFILE}
procedure Profile;
const
Digit_Test_Count = 3;
Digits_Default: array[0..Digit_Test_Count - 1] of Integer = (1000, 10000, 25000);
Digits_Multiply: array[0..Digit_Test_Count - 1] of Integer = (10, 50, 100);
Digits_PowerMod: array[0..Digit_Test_Count - 1] of Integer = (32, 64, 128);
var
A, B, C, D : HugeWord;
I, J, Di : Integer;
T : Word32;
begin
HugeWordInit(A);
HugeWordInit(B);
HugeWordInit(C);
HugeWordInit(D);
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(C, Di);
HugeWordRandom(D, Di - 2);
HugeWordAssign(B, D);
T := GetTickCount;
for I := 1 to 250000 do
begin
HugeWordAssign(A, C);
HugeWordAdd(A, B);
end;
T := GetTickCount - T;
Writeln('Add:':25, Di*32:10, ' ', 1000 / (T / 250000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
repeat
HugeWordRandom(C, Di);
HugeWordRandom(D, Di);
until HugeWordCompare(C, D) > 0;
HugeWordAssign(B, D);
T := GetTickCount;
for I := 1 to 100000 do
begin
HugeWordAssign(A, C);
HugeWordSubtract(A, B);
end;
T := GetTickCount - T;
Writeln('Sub:':25, Di*32:10, ' ', 1000 / (T / 100000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
repeat
HugeWordRandom(C, Di);
HugeWordRandom(D, Di);
until HugeWordCompare(C, D) > 0;
HugeWordAssign(B, D);
T := GetTickCount;
for I := 1 to 100000 do
begin
HugeWordAssign(A, C);
HugeWordSubtract_ALarger(A, B);
end;
T := GetTickCount - T;
Writeln('Sub_ALarger:':25, Di*32:10, ' ', 1000 / (T / 100000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
repeat
HugeWordRandom(A, Di);
HugeWordRandom(B, Di - 2);
until HugeWordCompare(A, B) > 0;
T := GetTickCount;
for I := 1 to 9000 do
HugeWordDivide(A, B, C, D);
T := GetTickCount - T;
Writeln('Div:':25, Di*32:10, ' ', 1000 / (T / 9000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(C, Di);
T := GetTickCount;
for I := 1 to 100000 do
begin
HugeWordAssign(A, C);
HugeWordShl1(A);
end;
T := GetTickCount - T;
Writeln('Shl1:':25, Di*32:10, ' ', 1000 / (T / 100000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
HugeWordRandom(A, Di);
HugeWordRandom(B, Di - 3);
T := GetTickCount;
for I := 1 to 10000 do
HugeWordMod(A, B, C);
T := GetTickCount - T;
Writeln('Mod:':25, Di*32:10, ' ', 1000 / (T / 10000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_PowerMod[J];
HugeWordRandom(A, Di);
HugeWordRandom(B, Di);
HugeWordRandom(C, Di);
T := GetTickCount;
for I := 1 to 1 do
begin
HugeWordPowerAndMod(D, A, B, C);
end;
T := GetTickCount - T;
Writeln('PowerAndMod:':25, Di*32:10, ' ', 1000 / (T / 1):0:5, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
HugeWordRandom(A, Di);
HugeWordRandom(B, Di);
T := GetTickCount;
for I := 1 to 1000000 do
HugeWordMultiply_Long(C, A, B);
T := GetTickCount - T;
Writeln('Mul_Long:':25, Di*32:10, ' ', 1000 / (T / 1000000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
HugeWordRandom(A, Di);
HugeWordRandom(B, Di);
T := GetTickCount;
for I := 1 to 20000 do
HugeWordMultiply_ShiftAdd_Unsafe(C, A, B);
T := GetTickCount - T;
Writeln('Mul_ShiftAdd:':25, Di*32:10, ' ', 1000 / (T / 20000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
HugeWordRandom(A, Di);
HugeWordRandom(B, Di);
T := GetTickCount;
for I := 1 to 50000 do
HugeWordMultiply_Karatsuba(C, A, B);
T := GetTickCount - T;
Writeln('Mul_Karatsuba:':25, Di*32:10, ' ', 1000 / (T / 50000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(A, Di);
HugeWordAssign(B, A);
T := GetTickCount;
for I := 1 to 250000 do
HugeWordEquals(A, B);
T := GetTickCount - T;
Writeln('Equals (worst case):':25, Di*32:10, ' ', 1000 / (T / 250000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
repeat
HugeWordRandom(A, Di);
HugeWordRandom(B, Di);
until HugeWordGetElement(A, 0) <> HugeWordGetElement(B, 0);
T := GetTickCount;
for I := 1 to 100000000 do
HugeWordCompare(A, B);
T := GetTickCount - T;
Writeln('Compare (best case):':25, Di*32:10, ' ', 1000 / (T / 100000000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(A, Di);
HugeWordAssign(B, A);
T := GetTickCount;
for I := 1 to 500000 do
HugeWordCompare(A, B);
T := GetTickCount - T;
Writeln('Compare (worst case):':25, Di*32:10, ' ', 1000 / (T / 500000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(A, Di);
HugeWordSetElement(A, Di - 1, 0);
T := GetTickCount;
for I := 1 to 10000000 do
HugeWordSetBitScanReverse(A);
T := GetTickCount - T;
Writeln('SetBitScanReverse:':25, Di*32:10, ' ', 1000 / (T / 10000000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Multiply[J];
HugeWordRandom(A, Di);
HugeWordAssign(B, A);
T := GetTickCount;
for I := 1 to 3000 do
begin
HugeWordAssign(A, B);
HugeWordISqrt(A);
end;
T := GetTickCount - T;
Writeln('ISqrt:':25, Di*32:10, ' ', 1000 / (T / 3000):0:1, '/s');
end;
for J := 0 to Digit_Test_Count - 1 do
begin
Di := Digits_Default[J];
HugeWordRandom(C, Di);
T := GetTickCount;
for I := 1 to 100000 do
begin
HugeWordAssign(A, C);
HugeWordShr1(A);
end;
T := GetTickCount - T;
Writeln('Shr1:':25, Di*32:10, ' ', 1000 / (T / 100000):0:1, '/s');
end;
HugeWordFinalise(D);
HugeWordFinalise(C);
HugeWordFinalise(B);
HugeWordFinalise(A);
end;
{$ENDIF}
end.