7641 lines
208 KiB
ObjectPascal
7641 lines
208 KiB
ObjectPascal
{******************************************************************************}
|
||
{ }
|
||
{ 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.
|
||
|