mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 14:40:30 +03:00
2271 lines
59 KiB
D
2271 lines
59 KiB
D
// Written in the D programming language.
|
|
|
|
/**
|
|
Provides a BigInt struct for multiprecision integer arithmetic.
|
|
|
|
The internal representation is binary, not decimal.
|
|
|
|
All relevant operators are overloaded.
|
|
|
|
Example:
|
|
----------------------------------------------------
|
|
BigInt a = "9588669891916142";
|
|
BigInt b = "7452469135154800";
|
|
auto c = a * b;
|
|
assert(c == "71459266416693160362545788781600");
|
|
auto d = b * a;
|
|
assert(d == "71459266416693160362545788781600");
|
|
assert(d == c);
|
|
d = c * "794628672112";
|
|
assert(d == "56783581982794522489042432639320434378739200");
|
|
auto e = c + d;
|
|
assert(e == "56783581982865981755459125799682980167520800");
|
|
auto f = d + c;
|
|
assert(f == e);
|
|
auto g = f - c;
|
|
assert(g == d);
|
|
g = f - d;
|
|
assert(g == c);
|
|
e = 12345678;
|
|
g = c + e;
|
|
auto h = g / b;
|
|
auto i = g % b;
|
|
assert(h == a);
|
|
assert(i == e);
|
|
----------------------------------------------------
|
|
|
|
Authors: Janice Caron
|
|
|
|
Date: 2008.05.18
|
|
|
|
License: Public Domain
|
|
|
|
|
|
Macros:
|
|
WIKI=Phobos/StdBigint
|
|
*/
|
|
|
|
module bigint;
|
|
|
|
import std.string : format;
|
|
import std.stdio : writef, writefln;
|
|
import std.algorithm : min, max, swap, reverse;
|
|
import std.traits : isIntegral;
|
|
import std.contracts : assumeUnique;
|
|
|
|
alias uint Digit; /// alias for uint
|
|
|
|
/******************
|
|
* Struct representing a multiprecision integer
|
|
*/
|
|
struct BigInt
|
|
{
|
|
Digits digits = [ cast(Digit)0 ];
|
|
|
|
static const BigInt ZERO = { [ cast(Digit)0 ] };
|
|
static const BigInt ONE = { [ cast(Digit)1 ] };
|
|
|
|
///
|
|
void opAssign(const BigInt n)
|
|
{
|
|
digits = n.digits;
|
|
}
|
|
|
|
///
|
|
void opAssign(int n)
|
|
{
|
|
digits = cast(Digits)( [ cast(Digit)n ] );
|
|
}
|
|
|
|
///
|
|
void opAssign(uint n)
|
|
{
|
|
static if(BIG_ENDIAN) { Digits a = [ cast(Digit)0, n ]; }
|
|
else { Digits a = [ cast(Digit)n, 0 ]; }
|
|
Big b = bigInt(a);
|
|
digits = b.digits;
|
|
}
|
|
|
|
///
|
|
void opAssign(long n)
|
|
{
|
|
static if(BIG_ENDIAN) { Digits a = [ cast(Digit)(n>>32), cast(Digit)n ]; }
|
|
else { Digits a = [ cast(Digit)n, cast(Digit)(n>>32) ]; }
|
|
Big b = bigInt(a);
|
|
digits = b.digits;
|
|
}
|
|
|
|
///
|
|
void opAssign(ulong n)
|
|
{
|
|
static if(BIG_ENDIAN) { Digits a = [ cast(Digit)0, cast(Digit)(n>>32), cast(Digit)n ]; }
|
|
else { Digits a = [ cast(Digit)n, cast(Digit)(n>>32), cast(Digit)0 ]; }
|
|
Big b = bigInt(a);
|
|
digits = b.digits;
|
|
}
|
|
|
|
///
|
|
void opAssign(string s)
|
|
{
|
|
Big b = fromString(s);
|
|
digits = b.digits;
|
|
}
|
|
|
|
///
|
|
static BigInt opCall(T)(T n)
|
|
{
|
|
BigInt r;
|
|
r.opAssign(n);
|
|
return r;
|
|
}
|
|
|
|
// Convert TO other types
|
|
|
|
///
|
|
void castTo(out BigInt r) const
|
|
{
|
|
r.digits = digits;
|
|
}
|
|
|
|
///
|
|
void castTo(out int r) const
|
|
{
|
|
r = cast(int)tail(digits,1u)[0];
|
|
}
|
|
|
|
///
|
|
void castTo(out uint r) const
|
|
{
|
|
r = cast(uint)tail(digits,1u)[0];
|
|
}
|
|
|
|
///
|
|
void castTo(out long r) const
|
|
{
|
|
ulong t;
|
|
castTo(t);
|
|
r = cast(long)t;
|
|
}
|
|
|
|
///
|
|
void castTo(out ulong r) const
|
|
{
|
|
mixin(setUp("x","this"));
|
|
r = peek(xp);
|
|
xp = next(xp);
|
|
if (xp != xe) r += cast(ulong)(peek(xp)) << 32;
|
|
}
|
|
|
|
///
|
|
void castTo(out string r) const
|
|
{
|
|
r = decimal(this);
|
|
}
|
|
|
|
// Unary operator overloads
|
|
|
|
///
|
|
BigInt opPos() const
|
|
{
|
|
BigInt r;
|
|
r.digits = digits;
|
|
return r;
|
|
}
|
|
|
|
///
|
|
BigInt opNeg() const
|
|
{
|
|
return neg(this);
|
|
}
|
|
|
|
///
|
|
BigInt opCom() const
|
|
{
|
|
return com(this);
|
|
}
|
|
|
|
///
|
|
BigInt opPostInc()
|
|
{
|
|
BigInt n = this;
|
|
opAddAssign(1);
|
|
return n;
|
|
}
|
|
|
|
///
|
|
BigInt opPostDec()
|
|
{
|
|
BigInt n = this;
|
|
opSubAssign(1);
|
|
return n;
|
|
}
|
|
|
|
// Binary operator overloads
|
|
|
|
///
|
|
BigInt opAdd(T)(T n) const
|
|
{
|
|
return opAdd(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opAdd(T:int)(T n) const
|
|
{
|
|
return add(this,cast(Digit)n);
|
|
}
|
|
|
|
///
|
|
BigInt opAdd(T:const(BigInt))(T n) const
|
|
{
|
|
return add(this,n);
|
|
}
|
|
|
|
///
|
|
void opAddAssign(T)(T n)
|
|
{
|
|
auto r = opAdd(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opSub(T)(T n) const
|
|
{
|
|
return opSub(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opSub(T:int)(T n) const
|
|
{
|
|
return sub(this,cast(Digit)n);
|
|
}
|
|
|
|
///
|
|
BigInt opSub(T:const(BigInt))(T n) const
|
|
{
|
|
return sub(this,n);
|
|
}
|
|
|
|
///
|
|
void opSubAssign(T)(T n)
|
|
{
|
|
auto r = opSub(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opMul(T)(T n) const
|
|
{
|
|
return opMul(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opMul(T:int)(T n) const
|
|
{
|
|
if (cast(int)n == int.min) return opMul(BigInt(n));
|
|
int xs = sgn;
|
|
if (xs == 0 || n == 0) return BigInt.ZERO;
|
|
int ys = n > 0 ? 1 : -1;
|
|
auto x = abs;
|
|
auto y = n > 0 ? n : -n;
|
|
auto r = mul(x,y);
|
|
return (xs == ys) ? r : -r;
|
|
}
|
|
|
|
///
|
|
BigInt opMul(T:const(BigInt))(T n) const
|
|
{
|
|
int xs = sgn;
|
|
int ys = n.sgn;
|
|
if (xs == 0 || ys == 0) return BigInt.ZERO;
|
|
auto x = abs;
|
|
auto y = n.abs;
|
|
auto r = mul(x,y);
|
|
return (xs == ys) ? r : -r;
|
|
}
|
|
|
|
///
|
|
void opMulAssign(T)(T n)
|
|
{
|
|
auto r = opMul(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
/*
|
|
Here's how the signs work
|
|
7 / 3 = 2
|
|
7 % 3 = 1
|
|
7 / -3 = -2
|
|
7 % -3 = 1
|
|
-7 / 3 = -2
|
|
-7 % 3 = -1
|
|
-7 / -3 = 2
|
|
-7 % -3 = -1
|
|
*/
|
|
|
|
///
|
|
BigInt opDiv(T)(T n) const
|
|
{
|
|
return opDiv(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opDiv(T:int)(T n) const
|
|
{
|
|
if (n == 0) throw new Exception("Divide by zero");
|
|
if (cast(int)n == int.min) return opDiv(BigInt(n));
|
|
int xs = sgn;
|
|
int ys = n > 0 ? 1 : -1;
|
|
if (xs == 0) return BigInt.ZERO;
|
|
auto x = abs;
|
|
auto y = n > 0 ? n : -n;
|
|
auto r = div(x,y);
|
|
return (xs == ys) ? r.q : -r.q;
|
|
}
|
|
|
|
///
|
|
BigInt opDiv(T:const(BigInt))(T n) const
|
|
{
|
|
int xs = sgn;
|
|
int ys = n.sgn;
|
|
if (ys == 0) throw new Exception("Divide by zero");
|
|
if (xs == 0) return BigInt.ZERO;
|
|
auto x = abs;
|
|
auto y = n.abs;
|
|
auto r = div(x,y);
|
|
return (xs == ys) ? r.q : -r.q;
|
|
}
|
|
|
|
///
|
|
void opDivAssign(T)(T n)
|
|
{
|
|
auto r = opDiv(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opMod(T)(T n) const
|
|
{
|
|
return opMod(BigInt(n));
|
|
}
|
|
|
|
///
|
|
int opMod(T:int)(T n) const
|
|
{
|
|
if (n == 0) throw new Exception("Divide by zero");
|
|
int xs = sgn;
|
|
if (xs == 0) return n;
|
|
auto x = abs;
|
|
auto y = n > 0 ? n : -n;
|
|
auto r = div(x,y);
|
|
return (xs == 1) ? r.r : -r.r;
|
|
}
|
|
|
|
///
|
|
BigInt opMod(T:const(BigInt))(T n) const
|
|
{
|
|
int xs = sgn;
|
|
int ys = n.sgn;
|
|
if (ys == 0) throw new Exception("Divide by zero");
|
|
if (xs == 0) return n;
|
|
auto x = abs;
|
|
auto y = n.abs;
|
|
auto r = div(x,y);
|
|
assert(r.r.abs < n.abs);
|
|
return (xs == 1) ? r.r : -r.r;
|
|
}
|
|
|
|
///
|
|
void opModAssign(T:int)(T n)
|
|
{
|
|
auto r = opMod(BigInt(n));
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
void opModAssign(T)(T n)
|
|
{
|
|
auto r = opMod(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opAnd(T)(T n) const
|
|
{
|
|
return opAnd(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opAnd(T:int)(T n) const
|
|
{
|
|
return and(this,cast(Digit)n);
|
|
}
|
|
|
|
///
|
|
uint opAnd(T:uint)(T n) const
|
|
{
|
|
uint t;
|
|
castTo(t);
|
|
return t & n;
|
|
}
|
|
|
|
///
|
|
BigInt opAnd(T:const(BigInt))(T n) const
|
|
{
|
|
return and(this,n);
|
|
}
|
|
|
|
///
|
|
void opAndAssign(T:uint)(T n)
|
|
{
|
|
auto r = opAnd(BigInt(n));
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
void opAndAssign(T)(T n)
|
|
{
|
|
auto r = opAnd(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opOr(T)(T n) const
|
|
{
|
|
return opOr(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opOr(T:int)(T n) const
|
|
{
|
|
return or(this,cast(Digit)n);
|
|
}
|
|
|
|
///
|
|
BigInt opOr(T:const(BigInt))(T n) const
|
|
{
|
|
return or(this,n);
|
|
}
|
|
|
|
///
|
|
void opOrAssign(T)(T n)
|
|
{
|
|
auto r = opOr(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opXor(T)(T n) const
|
|
{
|
|
return opXor(BigInt(n));
|
|
}
|
|
|
|
///
|
|
BigInt opXor(T:int)(T n) const
|
|
{
|
|
return xor(this,cast(Digit)n);
|
|
}
|
|
|
|
///
|
|
BigInt opXor(T:const(BigInt))(T n) const
|
|
{
|
|
return xor(this,n);
|
|
}
|
|
|
|
///
|
|
void opXorAssign(T)(T n)
|
|
{
|
|
auto r = opXor(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opShl(uint n) const
|
|
{
|
|
uint hi = n >> 5;
|
|
uint lo = n & 0x1F;
|
|
Big r = this;
|
|
if (lo != 0) r = shl(r,lo);
|
|
if (hi != 0) r = shlDigits(r,hi);
|
|
return r;
|
|
}
|
|
|
|
///
|
|
void opShlAssign(uint n)
|
|
{
|
|
auto r = opShl(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opShr(uint n) const
|
|
{
|
|
uint hi = n >> 5;
|
|
uint lo = n & 0x1F;
|
|
Big r = this;
|
|
if (lo != 0) r = shr(r,lo).q;
|
|
if (hi != 0) r = shrDigits(r,hi);
|
|
return r;
|
|
}
|
|
|
|
///
|
|
void opShrAssign(uint n)
|
|
{
|
|
auto r = opShr(n);
|
|
digits = r.digits;
|
|
}
|
|
|
|
///
|
|
BigInt opUShr(T)(T n) const
|
|
{
|
|
if (sgn >= 0) return opShr(n);
|
|
else throw new Exception(">>> cannot be applied to negative numbers");
|
|
}
|
|
|
|
///
|
|
void opUShrAssign(T)(T n)
|
|
{
|
|
if (sgn >= 0) opShrAssign(n);
|
|
else throw new Exception(">>>= cannot be applied to negative numbers");
|
|
}
|
|
|
|
///
|
|
int opEquals(T)(T n) const
|
|
{
|
|
return opEquals(BigInt(n));
|
|
}
|
|
|
|
///
|
|
int opEquals(T:int)(T n) const
|
|
{
|
|
return digits.length == 1 && digits[0] == n;
|
|
}
|
|
|
|
///
|
|
int opEquals(T:const(BigInt))(T n) const
|
|
{
|
|
return digits == n.digits;
|
|
}
|
|
|
|
///
|
|
int opCmp(T)(T n) const
|
|
{
|
|
return opCmp(BigInt(n));
|
|
}
|
|
|
|
///
|
|
int opCmp(T:int)(T n) const
|
|
{
|
|
int t = cmp(this,n);
|
|
return t == 0 ? 0 : (t > 0 ? 1 : -1);
|
|
}
|
|
|
|
///
|
|
int opCmp(T:const(BigInt))(T n) const
|
|
{
|
|
int t = cmp(this,n);
|
|
return t == 0 ? 0 : (t > 0 ? 1 : -1);
|
|
}
|
|
|
|
///
|
|
string toString() const
|
|
{
|
|
return decimal(this);
|
|
}
|
|
|
|
///
|
|
hash_t toHash() const
|
|
{
|
|
hash_t h = 0;
|
|
foreach(Digit d;digits) { h += d; }
|
|
return h;
|
|
}
|
|
|
|
private int sgn() const
|
|
{
|
|
int t = cmp(this,0);
|
|
return t == 0 ? 0 : (t > 0 ? 1 : -1);
|
|
}
|
|
|
|
private BigInt abs() const
|
|
{
|
|
return sgn >= 0 ? opPos : opNeg;
|
|
}
|
|
}
|
|
|
|
// ----------- EVERYTHING PRIVATE BEYOND THIS POINT -----------
|
|
private:
|
|
|
|
// Aliases and Typedefs
|
|
|
|
alias BigInt Big;
|
|
alias invariant(Digit)[] Digits;
|
|
typedef Digit[] DownArray;
|
|
typedef Digit* DownPtr;
|
|
alias int SignedDigit;
|
|
alias long SignedWideDigit;
|
|
alias Digit Unused;
|
|
typedef Digit[] UpArray;
|
|
typedef Digit* UpPtr;
|
|
alias ulong WideDigit;
|
|
|
|
struct Big_Digit { Big q; Digit r; }
|
|
struct Big_Big{ Big q; Big r; }
|
|
|
|
// Endianness
|
|
|
|
// The constant BIG_ENDIAN determines the ordering of digits within arrays.
|
|
// If BIG_ENDIAN is true, then bigints are stored most significant digit first.
|
|
// If BIG_ENDIAN is true, then bigints are stored most significant digit last.
|
|
|
|
// Note that this does not necessarily have to be the same as the endianness
|
|
// of the platform architecture.
|
|
|
|
// Setting BIG_ENDIAN opposite to platform endianness allows unittests
|
|
// to run in reverse endianness. (And they still pass).
|
|
|
|
version(BigEndian) { enum bool BIG_ENDIAN = true; }
|
|
else { enum bool BIG_ENDIAN = false; }
|
|
|
|
// String conversion
|
|
|
|
void parseError()
|
|
{
|
|
throw new Exception("Parse Error");
|
|
}
|
|
|
|
Big fromString(string s)
|
|
{
|
|
if (s.length == 0) parseError();
|
|
if (s[0] == '-')
|
|
{
|
|
return -fromString(s[1..$]);
|
|
}
|
|
if (s.length > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
|
|
{
|
|
return fromHex(s[2..$]);
|
|
}
|
|
return fromDecimal(s);
|
|
}
|
|
|
|
Big fromDecimal(string s)
|
|
{
|
|
bool invalid = true;
|
|
Big r = Big.ZERO;
|
|
foreach(char c;s)
|
|
{
|
|
if (c == '_') continue;
|
|
if (c < '0' || c > '9') parseError();
|
|
invalid = false;
|
|
//r = 10 * r + (c - '0');
|
|
r *= 10;
|
|
r += (c - '0');
|
|
}
|
|
if (invalid) parseError();
|
|
return r;
|
|
}
|
|
|
|
Big fromHex(string s)
|
|
{
|
|
bool invalid = true;
|
|
Big r = Big.ZERO;
|
|
foreach(char c;s)
|
|
{
|
|
switch(c)
|
|
{
|
|
case '_':
|
|
continue;
|
|
|
|
case '0','1','2','3','4','5','6','7','8','9':
|
|
r = (r << 4) + (c - '0');
|
|
invalid = false;
|
|
break;
|
|
|
|
case 'A','B','C','D','E','F':
|
|
r = (r << 4) + (c - 'A' + 10);
|
|
invalid = false;
|
|
break;
|
|
|
|
case 'a','b','c','d','e','f':
|
|
r = (r << 4) + (c - 'a' + 10);
|
|
invalid = false;
|
|
break;
|
|
|
|
default:
|
|
parseError();
|
|
}
|
|
}
|
|
if (invalid) parseError();
|
|
return r;
|
|
}
|
|
|
|
string decimal(Big b)
|
|
{
|
|
if (b == 0) return "0";
|
|
if (b < 0) return "-" ~ decimal(-b);
|
|
|
|
char[] result;
|
|
while (b != Big.ZERO) {
|
|
auto t = div(b, 10);
|
|
b = t.q;
|
|
result ~= cast(char)(t.r + '0');
|
|
}
|
|
reverse(result);
|
|
return assumeUnique(result);
|
|
}
|
|
|
|
// Shrinking
|
|
|
|
Big bigInt(DownArray a)
|
|
{
|
|
if (a.length == 0) return Big.ZERO;
|
|
|
|
Big r;
|
|
|
|
if (a.length == 1)
|
|
{
|
|
r.digits = cast(Digits)a;
|
|
}
|
|
else
|
|
{
|
|
auto xp = begin(a);
|
|
auto xe = end(a);
|
|
auto d1 = peek(xp);
|
|
xp = next(xp);
|
|
auto s = signOf(d1);
|
|
while (xp != xe)
|
|
{
|
|
if (d1 != s) break;
|
|
auto d2 = peek(xp);
|
|
if (signOf(d2) != s) break;
|
|
xp = next(xp);
|
|
d1 = d2;
|
|
}
|
|
r.digits = freezeRange(xp, xe);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static if(BIG_ENDIAN)
|
|
{
|
|
alias UpArray BwdArray;
|
|
alias UpPtr BwdPtr;
|
|
alias DownArray FwdArray;
|
|
alias DownPtr FwdPtr;
|
|
|
|
Digit[] join(Digit[] t, Digit[] u) { return t ~ u; }
|
|
T head(T)(T t,size_t n) { return cast(T)(t[0..n]); }
|
|
T tail(T)(T t,size_t n) { return cast(T)(t[$-n..$]); }
|
|
}
|
|
else
|
|
{
|
|
alias DownArray BwdArray;
|
|
alias DownPtr BwdPtr;
|
|
alias UpArray FwdArray;
|
|
alias UpPtr FwdPtr;
|
|
|
|
Digit[] join(Digit[] t, Digit[] u) { return u ~ t; }
|
|
T head(T)(T t,size_t n) { return cast(T)(t[$-n..$]); }
|
|
T tail(T)(T t,size_t n) { return cast(T)(t[0..n]); }
|
|
}
|
|
|
|
// Really simple functions
|
|
|
|
FwdPtr advance(FwdPtr p,size_t n) { return p + n; }
|
|
BwdPtr advance(BwdPtr p,size_t n) { return p - n; }
|
|
|
|
Digit begin(Digit a) { return a; }
|
|
FwdPtr begin(FwdArray a) { return cast(FwdPtr)(a.ptr); }
|
|
BwdPtr begin(BwdArray a) { return cast(BwdPtr)(a.ptr + a.length - 1); }
|
|
|
|
Big bigInt(Digit a) { Digit[] t; t.length = 1; t[0] = a; return bigInt(cast(DownArray)t); }
|
|
Big bigInt(Digits a) { return bigInt(cast(DownArray)a); }
|
|
Big bigInt(Digit[] a) { return bigInt(cast(DownArray)a); }
|
|
Big bigInt(UpArray a) { return bigInt(cast(DownArray)a); }
|
|
|
|
Digit downArray(Digit a) { return a; }
|
|
DownArray downArray(Digit[] a) { return cast(DownArray)a; }
|
|
DownArray downArray(Big a) { return cast(DownArray)(a.digits); }
|
|
|
|
Digit end(Digit a) { return a; }
|
|
FwdPtr end(FwdArray a) { return cast(FwdPtr)(a.ptr + a.length); }
|
|
BwdPtr end(BwdArray a) { return cast(BwdPtr)(a.ptr + - 1); }
|
|
|
|
Digit first(Digit a) { return a; }
|
|
Digit first(FwdArray a) { return a[0]; }
|
|
Digit first(BwdArray a) { return a[$-1]; }
|
|
|
|
Digits freezeRange(FwdPtr p, FwdPtr q) { return cast(Digits)((p-1)[0..(q-p+1)]); }
|
|
Digits freezeRange(BwdPtr p, BwdPtr q) { return cast(Digits)((q+1)[0..(p-q+1)]); }
|
|
|
|
Digit last(Digit a) { return a; }
|
|
Digit last(FwdArray a) { return a[$-1]; }
|
|
Digit last(BwdArray a) { return a[0]; }
|
|
|
|
Digit lsd(Digit a) { return a; }
|
|
Digit lsd(DownArray a) { return last(a); }
|
|
Digit lsd(UpArray a) { return first(a); }
|
|
|
|
Digit msd(Digit a) { return a; }
|
|
Digit msd(DownArray a) { return first(a); }
|
|
Digit msd(UpArray a) { return last(a); }
|
|
|
|
size_t lengthOf(Digit a) { return 1; }
|
|
size_t lengthOf(Big a) { return a.digits.length; }
|
|
size_t lengthOf(DownArray a) { return a.length; }
|
|
size_t lengthOf(UpArray a) { return a.length; }
|
|
|
|
Digit next(ulong d) { return cast(Digit)d; }
|
|
Digit next(Digit d) { return d; }
|
|
FwdPtr next(FwdPtr p) { return p + 1; }
|
|
BwdPtr next(BwdPtr p) { return p - 1; }
|
|
|
|
Digit peek(ulong d) { return cast(Digit)d; }
|
|
Digit peek(Digit d) { return d; }
|
|
Digit peek(Digit* p) { return *p; }
|
|
|
|
void poke(DownPtr p,Digit d) { *p = d; }
|
|
void poke(DownPtr p,WideDigit d) { *p = cast(Digit)d; }
|
|
void poke(DownPtr p,SignedWideDigit d) { *p = cast(Digit)d; }
|
|
void poke(UpPtr p,Digit d) { *p = d; }
|
|
void poke(UpPtr p,WideDigit d) { *p = cast(Digit)d; }
|
|
void poke(UpPtr p,SignedWideDigit d) { *p = cast(Digit)d; }
|
|
|
|
Big shrink(Big a) { return bigInt(cast(DownArray)(a.digits)); }
|
|
|
|
FwdArray slice(FwdPtr ptr, size_t len) { return cast(FwdArray)(ptr[0..len]); }
|
|
BwdArray slice(BwdPtr ptr, size_t len) { return cast(BwdArray)((ptr-len+1)[0..len]); }
|
|
|
|
Digit signOf(SignedDigit d) { return d < 0 ? -1 : 0; }
|
|
|
|
Digit upArray(Digit a) { return a; }
|
|
UpArray upArray(Digit[] a) { return cast(UpArray)a; }
|
|
UpArray upArray(in Big a) { return cast(UpArray)(a.digits); }
|
|
|
|
// Core functions
|
|
|
|
WideDigit addCore(Digit x,Digit y,WideDigit c) { return (c + x) + y; }
|
|
|
|
Digit andCore(Digit x,Digit y,Digit c) { return x & y; }
|
|
|
|
WideDigit divCore(Digit x,Digit y,WideDigit c)
|
|
{
|
|
c <<= 32;
|
|
c += x;
|
|
WideDigit r = c % y;
|
|
c /= y;
|
|
c += r << 32;
|
|
return c;
|
|
}
|
|
|
|
WideDigit shlCore(Digit x,Digit y,WideDigit c) { return c + (cast(WideDigit)x << y); }
|
|
|
|
WideDigit shrCore(Digit x,Digit y,WideDigit c) { return c + (x >> y) + (cast(WideDigit)x << (64-y)); }
|
|
|
|
WideDigit mulCore(Digit x,Digit y,WideDigit c) { return c + (cast(WideDigit)x * y); }
|
|
|
|
WideDigit subCore(Digit x,Digit y,WideDigit c) { return (c + x) - y; }
|
|
|
|
Digit orCore(Digit x,Digit y,Digit c) { return x | y; }
|
|
|
|
Digit xorCore(Digit x,Digit y,Digit c) { return x ^ y; }
|
|
|
|
// Update functions
|
|
|
|
Digit updateDigit(Digit c) { return c; }
|
|
|
|
WideDigit updateShr(WideDigit c) { return cast(WideDigit)(cast(SignedWideDigit)c >> 32); }
|
|
|
|
WideDigit updateUShr(WideDigit c) { return c >> 32; }
|
|
|
|
// Helper functions
|
|
|
|
int cmp(DownPtr xp, DownPtr xe, DownPtr yp)
|
|
{
|
|
while (xp != xe)
|
|
{
|
|
auto xd = peek(xp);
|
|
auto yd = peek(yp);
|
|
if (xd < yd) return -1;
|
|
if (xd > yd) return 1;
|
|
xp = next(xp);
|
|
yp = next(yp);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mulInner(Big a, UpPtr rp, WideDigit y)
|
|
{
|
|
WideDigit c;
|
|
mixin(setUp("x","a"));
|
|
|
|
while (xp != xe)
|
|
{
|
|
c += y * peek(xp) + peek(rp);
|
|
poke(rp,c);
|
|
xp = next(xp);
|
|
rp = next(rp);
|
|
c = updateShr(c);
|
|
}
|
|
|
|
mixin(runOnce( "mulCore","updateShr","xs","y"));
|
|
}
|
|
|
|
void divInner(DownPtr xp, DownPtr cachePtr, size_t len)
|
|
{
|
|
Digit result;
|
|
|
|
debug // sanity checking
|
|
{
|
|
DownArray _divisor = slice(cachePtr,32*len);
|
|
_divisor = tail(_divisor,len);
|
|
}
|
|
|
|
DownPtr rp = xp;
|
|
xp = next(xp);
|
|
DownPtr xe = advance(xp,len);
|
|
|
|
debug // sanity checking
|
|
{
|
|
DownArray _remainder = slice(xp,len); // will be modified in-place
|
|
DownArray _original = cast(DownArray)_remainder.dup; // but we'll keep this one
|
|
}
|
|
|
|
for (Digit mask=0x80000000; mask!=0; mask>>=1)
|
|
{
|
|
int t = cmp(xp,xe,cachePtr);
|
|
if (t >= 0)
|
|
{
|
|
debug // sanity checking
|
|
{
|
|
DownArray _after = slice(xp,len); // will be modified in-place
|
|
DownArray _before = cast(DownArray)_after.dup; // but we'll keep this one
|
|
DownArray _test = slice(cachePtr,len);
|
|
}
|
|
|
|
result += mask;
|
|
Digit carry = subInPlace(xp,cachePtr,len);
|
|
debug
|
|
{
|
|
BigInt before = bigInt(_before);
|
|
BigInt test = bigInt(_test);
|
|
BigInt after = bigInt(_after);
|
|
|
|
assert(after + test == before);
|
|
assert(carry == 0);
|
|
}
|
|
}
|
|
cachePtr = advance(cachePtr,len);
|
|
}
|
|
|
|
debug // sanity checking
|
|
{
|
|
// in theory, quotient * _divisor + _remainder == _original
|
|
BigInt quotient = result;
|
|
BigInt divisor = bigInt(_divisor);
|
|
BigInt remainder = bigInt(_remainder);
|
|
BigInt original = bigInt(_original);
|
|
|
|
assert(quotient * divisor + remainder == original);
|
|
}
|
|
|
|
poke(rp,result);
|
|
}
|
|
|
|
Digit subInPlace(DownPtr downPtrX, DownPtr downPtrY, size_t len)
|
|
{
|
|
UpPtr xp = cast(UpPtr)(advance(downPtrX,len-1));
|
|
UpPtr yp = cast(UpPtr)(advance(downPtrY,len-1));
|
|
UpPtr xe = advance(xp,len);
|
|
|
|
SignedWideDigit c;
|
|
|
|
while (xp != xe)
|
|
{
|
|
c += peek(xp);
|
|
c -= peek(yp);
|
|
poke(xp,c);
|
|
c >>= 32;
|
|
xp = next(xp);
|
|
yp = next(yp);
|
|
}
|
|
|
|
return cast(Digit)c;
|
|
}
|
|
|
|
DownPtr makeDivCache(DownArray y)
|
|
{
|
|
// Pad with a leading zero
|
|
auto paddedY = cast(UpArray)(join([Digit.init],y));
|
|
|
|
auto upCache = cast(UpArray)new Digit[32 * paddedY.length];
|
|
auto rp = begin(upCache);
|
|
|
|
// Fill upCache by successively leftshifting x by one bit
|
|
for (int i=0; i<32; ++i)
|
|
{
|
|
auto xp = begin(paddedY);
|
|
auto xe = end(paddedY);
|
|
|
|
WideDigit c;
|
|
|
|
// Shift lefy by one bit
|
|
while (xp != xe)
|
|
{
|
|
Digit xd = peek(xp);
|
|
poke(rp,xd);
|
|
c += xd;
|
|
c += xd;
|
|
poke(xp,c);
|
|
c >>= 32;
|
|
xp = next(xp);
|
|
rp = next(rp);
|
|
}
|
|
}
|
|
|
|
auto downCache = cast(DownArray)upCache;
|
|
|
|
static if(false) // make true to display cache
|
|
{
|
|
for (int j=0; j<32; ++j)
|
|
{
|
|
writefln("bit %02d: ",31-j,hex(downCache[paddedY.length*j..paddedY.length*(j+1)]));
|
|
}
|
|
}
|
|
|
|
return begin(downCache);
|
|
}
|
|
|
|
// Mixins
|
|
|
|
string runOnce(string core, string updater, string xp, string yp)
|
|
{
|
|
return
|
|
"{
|
|
auto xd = peek("~xp~");
|
|
auto yd = peek("~yp~");
|
|
c = "~core~"(xd,yd,c);
|
|
poke(rp,c);
|
|
"~xp~" = next("~xp~");
|
|
"~yp~" = next("~yp~");
|
|
rp = next(rp);
|
|
c = "~updater~"(c);
|
|
}";
|
|
}
|
|
|
|
string runTo(string dest, string core, string updater, string xp, string yp)
|
|
{
|
|
string s = runOnce(core,updater,xp,yp);
|
|
return
|
|
"
|
|
static if(isIntegral!(typeof("~dest~"))) {"~s~"}
|
|
else
|
|
{
|
|
while("~dest[0..1]~"p!="~dest~") {"~s~"}
|
|
}
|
|
";
|
|
}
|
|
|
|
string setDown(string x,string a)
|
|
{
|
|
return
|
|
"
|
|
auto "~x~" = downArray("~a~");
|
|
auto "~x~"p = begin("~x~");
|
|
auto "~x~"e = end("~x~");
|
|
auto "~x~"s = signOf(msd("~x~"));
|
|
";
|
|
}
|
|
|
|
string setUp(string x,string a)
|
|
{
|
|
return
|
|
"
|
|
auto "~x~" = upArray("~a~");
|
|
auto "~x~"p = begin("~x~");
|
|
auto "~x~"e = end("~x~");
|
|
auto "~x~"s = signOf(msd("~x~"));
|
|
";
|
|
}
|
|
|
|
// BigInt functions
|
|
|
|
Big neg(Big b)
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(b) + 1]);
|
|
auto rp = begin(r);
|
|
|
|
SignedDigit a;
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runOnce( "subCore","updateShr","xp","yp"));
|
|
mixin(runTo("ye","subCore","updateShr","xs","yp"));
|
|
mixin(runOnce( "subCore","updateShr","xs","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big com(Big a)
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(a)]);
|
|
auto rp = begin(r);
|
|
|
|
Digit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
Digit ys = uint.max;
|
|
|
|
mixin(runTo("xe","xorCore","updateDigit","xp","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big add(Other)(Big a,Other b)
|
|
{
|
|
static if(is(Other==BigInt)) if (lengthOf(a) < lengthOf(b))
|
|
{
|
|
swap(a,b);
|
|
}
|
|
auto r = upArray(new Digit[max(lengthOf(a),lengthOf(b)) + 1]);
|
|
auto rp = begin(r);
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runTo("ye","addCore","updateShr","xp","yp"));
|
|
mixin(runTo("xe","addCore","updateShr","xp","ys"));
|
|
mixin(runOnce( "addCore","updateShr","xs","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big sub(Big a,Big b)
|
|
{
|
|
auto r = upArray(new Digit[max(lengthOf(a),lengthOf(b)) + 1]);
|
|
auto rp = begin(r);
|
|
auto re = advance(rp,min(lengthOf(a),lengthOf(b)));
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runTo("re","subCore","updateShr","xp","yp"));
|
|
if (lengthOf(x) >= lengthOf(y))
|
|
{
|
|
mixin(runTo("xe","subCore","updateShr","xp","ys"));
|
|
}
|
|
else
|
|
{
|
|
mixin(runTo("ye","subCore","updateShr","xs","yp"));
|
|
}
|
|
mixin(runOnce("subCore","updateShr","xs","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big sub(Big a, Digit b)
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(a) + 1]);
|
|
auto rp = begin(r);
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runOnce( "subCore","updateShr","xp","yp"));
|
|
mixin(runTo("xe","subCore","updateShr","xp","ys"));
|
|
mixin(runOnce( "subCore","updateShr","xs","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big mul(Big a, Big b) // a and b must be positive
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(a) + lengthOf(b)]);
|
|
auto rp = begin(r);
|
|
|
|
mixin(setUp("y","b"));
|
|
while (yp != ye)
|
|
{
|
|
mulInner(a,rp,peek(yp));
|
|
yp = next(yp);
|
|
rp = next(rp);
|
|
}
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big mul(Big a, Digit b) // a and b must be positive
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(a) + 1]);
|
|
auto rp = begin(r);
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
|
|
mixin(runTo("xe","mulCore","updateShr","xp","b"));
|
|
poke(rp,c);
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big_Big div(Big a, Big b) // a and b must be positive
|
|
{
|
|
auto lenX = lengthOf(a);
|
|
auto lenY = lengthOf(b) + 1;
|
|
|
|
auto r = cast(DownArray)join(new Digit[lenY], cast(Digit[])a.digits);
|
|
auto rp = begin(r);
|
|
auto re = advance(rp,lenX);
|
|
|
|
auto y = downArray(b);
|
|
auto cache = makeDivCache(y);
|
|
|
|
while (rp != re)
|
|
{
|
|
divInner(rp, cache, lenY);
|
|
rp = next(rp);
|
|
}
|
|
|
|
Big quotient = bigInt(cast(DownArray)(head(r,lenX)));
|
|
Big remainder = bigInt(cast(DownArray)(tail(r,lenY)));
|
|
|
|
return Big_Big(quotient,remainder);
|
|
}
|
|
|
|
Big_Digit div(Big a, Digit b) // a and b must be positive
|
|
{
|
|
auto r = downArray(new Digit[lengthOf(a)]);
|
|
auto rp = begin(r);
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setDown("x","a"));
|
|
|
|
mixin(runTo("xe","divCore","updateUShr","xp","b"));
|
|
|
|
return Big_Digit(bigInt(r),cast(Digit)c);
|
|
}
|
|
|
|
Big and(Other)(Big a, Other b)
|
|
{
|
|
static if(is(Other==BigInt)) if (lengthOf(a) < lengthOf(b)) { swap(a,b); }
|
|
auto r = upArray(new Digit[max(lengthOf(a),lengthOf(b))]);
|
|
auto rp = begin(r);
|
|
|
|
Digit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runTo("ye","andCore","updateDigit","xp","yp"));
|
|
mixin(runTo("xe","andCore","updateDigit","xp","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big or(Other)(Big a, Other b)
|
|
{
|
|
static if(is(Other==BigInt)) if (lengthOf(a) < lengthOf(b)) { swap(a,b); }
|
|
auto r = upArray(new Digit[max(lengthOf(a),lengthOf(b))]);
|
|
auto rp = begin(r);
|
|
|
|
Digit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runTo("ye","orCore","updateDigit","xp","yp"));
|
|
mixin(runTo("xe","orCore","updateDigit","xp","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big xor(Other)(Big a, Other b)
|
|
{
|
|
static if(is(Other==BigInt)) if (lengthOf(a) < lengthOf(b)) { swap(a,b); }
|
|
auto r = upArray(new Digit[max(lengthOf(a),lengthOf(b))]);
|
|
auto rp = begin(r);
|
|
|
|
Digit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
mixin(setUp("y","b"));
|
|
|
|
mixin(runTo("ye","xorCore","updateDigit","xp","yp"));
|
|
mixin(runTo("xe","xorCore","updateDigit","xp","ys"));
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big shl(Big a, Digit b)
|
|
{
|
|
auto r = upArray(new Digit[lengthOf(a) + 1]);
|
|
auto rp = begin(r);
|
|
|
|
WideDigit c;
|
|
|
|
mixin(setUp("x","a"));
|
|
|
|
mixin(runTo("xe","shlCore","updateShr","xp","b"));
|
|
poke(rp,c);
|
|
|
|
return bigInt(r);
|
|
}
|
|
|
|
Big shlDigits(Big a, uint n)
|
|
{
|
|
Big b;
|
|
b.digits = cast(Digits)join(a.digits.dup, new Digit[n]);
|
|
return b;
|
|
}
|
|
|
|
Big_Digit shr(Big a, Digit b)
|
|
{
|
|
auto r = downArray(new Digit[lengthOf(a)]);
|
|
auto rp = begin(r);
|
|
|
|
mixin(setDown("x","a"));
|
|
|
|
WideDigit c = (signOf(msd(x)) << (32-b)) & uint.max;
|
|
|
|
mixin(runTo("xe","shrCore","updateUShr","xp","b"));
|
|
|
|
return Big_Digit(bigInt(r),cast(Digit)(c >> (32-b)));
|
|
}
|
|
|
|
Big shrDigits(Big a, uint n)
|
|
{
|
|
if (lengthOf(a) < n)
|
|
{
|
|
return bigInt(signOf(msd(downArray(a))));
|
|
}
|
|
Big b;
|
|
b.digits = cast(Digits)head(a.digits, a.digits.length-n);
|
|
return b;
|
|
}
|
|
|
|
int cmp(Big a, Big b) // assumes a and b are both shrunk
|
|
{
|
|
mixin(setDown("x","a"));
|
|
mixin(setDown("y","b"));
|
|
|
|
if (xs != ys) return xs - ys;
|
|
|
|
if (lengthOf(x) > lengthOf(y)) return cast(SignedDigit)xs < 0 ? -1 : 1;
|
|
if (lengthOf(x) < lengthOf(y)) return cast(SignedDigit)ys < 0 ? 1 : -1;
|
|
|
|
return cmp(xp,xe,yp);
|
|
}
|
|
|
|
int cmp(Big a, Digit b) // assumes a is shrunk
|
|
{
|
|
mixin(setDown("x","a"));
|
|
Digit ys = signOf(b);
|
|
|
|
if (xs != ys) return xs - ys;
|
|
|
|
if (lengthOf(x) > 1) return cast(SignedDigit)xs < 0 ? -1 : 1;
|
|
|
|
return peek(xp) - b;
|
|
}
|
|
|
|
// Debugging functions
|
|
|
|
Big makeBig(Digits array...)
|
|
{
|
|
Big r;
|
|
static if(BIG_ENDIAN)
|
|
{
|
|
r.digits = array;
|
|
}
|
|
else
|
|
{
|
|
r.digits = cast(Digits)(array.dup.reverse);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
string hex(Big x)
|
|
{
|
|
return "\r" ~ hex(x.digits);
|
|
}
|
|
|
|
string hex(in Digit[] x)
|
|
{
|
|
string r;
|
|
static if(BIG_ENDIAN)
|
|
{
|
|
auto array = x;
|
|
}
|
|
else
|
|
{
|
|
auto array = x.dup.reverse;
|
|
}
|
|
for (int i=array.length; i<4; ++i)
|
|
{
|
|
r ~= "----------, ";
|
|
}
|
|
foreach(d;array)
|
|
{
|
|
r ~= format("0x%08X, ",d);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
string dump(string name)
|
|
{
|
|
return
|
|
"{ writef(\"(%d) "~name~" = \",__LINE__);
|
|
static if(is(typeof("~name~") == Digit)) writefln(\"Digit %08X\","~name~");
|
|
else static if(is(typeof("~name~") == WideDigit)) writefln(\"WideDigit %016X\","~name~");
|
|
else static if(is(typeof("~name~") == SignedDigit)) writefln(\"SignedDigit %08X\","~name~");
|
|
else static if(is(typeof("~name~") == SignedWideDigit)) writefln(\"SignedWideDigit %016X\","~name~");
|
|
else writefln(typeof("~name~").stringof,\" \","~name~");
|
|
}";
|
|
}
|
|
|
|
void diag(int line = __LINE__, string file = __FILE__)
|
|
{
|
|
writefln("%s(%d) executed.", file, line);
|
|
}
|
|
|
|
// Unittests
|
|
|
|
debug unittest
|
|
{
|
|
// This block of unittests demonstrates that we can shrink arrays correctly
|
|
{
|
|
auto a = makeBig( 0x00000000 );
|
|
auto r = shrink(a);
|
|
assert(r.digits == a.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0xFFFFFFFF );
|
|
auto r = shrink(a);
|
|
assert(r.digits == a.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0x44444444 );
|
|
auto r = shrink(a);
|
|
assert(r.digits == a.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0xCCCCCCCC );
|
|
auto r = shrink(a);
|
|
assert(r.digits == a.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0x00000000, 0x00000000, 0x44444444, 0x44444444 );
|
|
auto b = makeBig( 0x44444444, 0x44444444 );
|
|
auto r = shrink(a);
|
|
assert(r.digits == b.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0x00000000, 0x00000000, 0xCCCCCCCC, 0xCCCCCCCC );
|
|
auto b = makeBig( 0x00000000, 0xCCCCCCCC, 0xCCCCCCCC );
|
|
auto r = shrink(a);
|
|
assert(r.digits == b.digits, hex(r));
|
|
}{
|
|
auto a = makeBig( 0xFFFFFFFF, 0xFFFFFFFF, 0x44444444, 0x44444444 );
|
|
auto b = makeBig( 0xFFFFFFFF, 0x44444444, 0x44444444 );
|
|
auto r = shrink(a);
|
|
assert(r.digits == b.digits, hex(r));
|
|
}
|
|
// This block of unittests demonstrates that neg(Big) works
|
|
{
|
|
auto x = makeBig( 0x66666666, 0x66666660 );
|
|
auto z = makeBig( 0x99999999, 0x999999A0 );
|
|
auto r = neg(x);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x80000000, 0x00000000 );
|
|
auto z = makeBig( 0x00000000, 0x80000000, 0x00000000 );
|
|
auto r = neg(x);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x00000000, 0x80000000, 0x00000000 );
|
|
auto z = makeBig( 0x80000000, 0x00000000 );
|
|
auto r = neg(x);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that com(Big) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto z = makeBig( 0xFEDCBA98, 0x76543210 );
|
|
auto r = com(x);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that add(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x66666666, 0x66666660 );
|
|
auto y = makeBig( 0x77777777, 0x77777770 );
|
|
auto z = makeBig( 0x00000000, 0xDDDDDDDD, 0xDDDDDDD0 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x99999999, 0x99999990 );
|
|
auto y = makeBig( 0xAAAAAAAA, 0xAAAAAAA0 );
|
|
auto z = makeBig( 0xFFFFFFFF, 0x44444444, 0x44444430 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0xEEEEEEEE, 0xEEEEEEE0 );
|
|
auto y = makeBig( 0x66666666, 0x66666660 );
|
|
auto z = makeBig( 0x55555555, 0x55555540 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x99999999, 0x99999990 );
|
|
auto y = makeBig( 0x66666666, 0x66666660 );
|
|
auto z = makeBig( 0xFFFFFFF0 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that add(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x66666666, 0x66666660 );
|
|
auto y = 0x77777770 ;
|
|
auto z = makeBig( 0x66666666, 0xDDDDDDD0 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x99999999, 0x99999990 );
|
|
auto y = 0xAAAAAAA0 ;
|
|
auto z = makeBig( 0x99999999, 0x44444430 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0xEEEEEEEE, 0xEEEEEEE0 );
|
|
auto y = 0x66666660 ;
|
|
auto z = makeBig( 0xEEEEEEEF, 0x55555540 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x99999999, 0x99999990 );
|
|
auto y = 0x66666660 ;
|
|
auto z = makeBig( 0x99999999, 0xFFFFFFF0 );
|
|
auto r = add(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that sub(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x22222222, 0x22222222, 0x22222222 );
|
|
auto y = makeBig( 0x11111111, 0x11111111 );
|
|
auto z = makeBig( 0x22222222, 0x11111111, 0x11111111 );
|
|
auto r = sub(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x22222222, 0x22222222 );
|
|
auto y = makeBig( 0x11111111, 0x11111111, 0x11111111 );
|
|
auto z = makeBig( 0xEEEEEEEF, 0x11111111, 0x11111111 );
|
|
auto r = sub(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that sub(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x22222222, 0x22222222 );
|
|
auto y = 0x11111111 ;
|
|
auto z = makeBig( 0x22222222, 0x11111111 );
|
|
auto r = sub(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x22222222, 0x22222222 );
|
|
auto y = 0x80000000 ;
|
|
auto z = makeBig( 0x22222222, 0xA2222222 );
|
|
auto r = sub(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that mul(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x01111111, 0x11111111 );
|
|
auto y = makeBig( 0x01111111, 0x11111111 );
|
|
auto z = makeBig( 0x00012345, 0x6789ABCD, 0xEFEDCBA9, 0x87654321 );
|
|
auto r = mul(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that mul(Big,uint) works
|
|
{
|
|
auto x = makeBig( 0x11111111, 0x11111111 );
|
|
auto y = 0x11111111 ;
|
|
auto z = makeBig( 0x01234567, 0x88888888, 0x87654321 );
|
|
auto r = mul(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that div(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x00000014 );
|
|
auto y = makeBig( 0x00000007 );
|
|
auto z = makeBig( 0x00000002 );
|
|
auto w = makeBig( 0x00000006 );
|
|
auto t = div(x,y);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r.digits == w.digits, hex(t.r));
|
|
}{
|
|
auto x = makeBig( 0x00012345, 0x6789ABCD, 0xEFEDCBA9, 0x87654321 );
|
|
auto y = makeBig( 0x01111111, 0x11111111 );
|
|
auto z = makeBig( 0x01111111, 0x11111111 );
|
|
auto w = makeBig( 0x00000000 );
|
|
auto t = div(x,y);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r.digits == w.digits, hex(t.r));
|
|
}{
|
|
auto x = makeBig( 0x00012345, 0x6789ABCD, 0xEFEDCBA9, 0x98765432 );
|
|
auto y = makeBig( 0x01111111, 0x11111111 );
|
|
auto z = makeBig( 0x01111111, 0x11111111 );
|
|
auto w = makeBig( 0x11111111 );
|
|
auto t = div(x,y);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r.digits == w.digits, hex(t.r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that div(Big,uint) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0x01234567 ;
|
|
auto z = makeBig( 0x00000001, 0x00000079 );
|
|
auto t = div(x,y);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r == 0x00000040, format("remainder = %08X",t.r));
|
|
}{
|
|
auto x = makeBig( 0x00000000, 0xAB54A98C, 0xEB1F0AD2 );
|
|
auto y = 0x0000000A ;
|
|
auto z = makeBig( 0x112210F4, 0x7DE98115 );
|
|
auto t = div(x,y);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r == 0x00000000, format("remainder = %08X",t.r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that and(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333, 0X33333333 );
|
|
auto z = makeBig( 0x01230123, 0x01230123 );
|
|
auto r = and(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333 );
|
|
auto z = makeBig( 0x01230123 );
|
|
auto r = and(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0XCCCCCCCC );
|
|
auto z = makeBig( 0x01234567, 0x8888CCCC );
|
|
auto r = and(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that and(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0X33333333 ;
|
|
auto z = makeBig( 0x01230123 );
|
|
auto r = and(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0XCCCCCCCC ;
|
|
auto z = makeBig( 0x01234567, 0x8888CCCC );
|
|
auto r = and(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that or(Big,Big) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333, 0X33333333 );
|
|
auto z = makeBig( 0x33337777, 0xBBBBFFFF );
|
|
auto r = or(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333 );
|
|
auto z = makeBig( 0x01234567, 0xBBBBFFFF );
|
|
auto r = or(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0XCCCCCCCC );
|
|
auto z = makeBig( 0xCDEFCDEF );
|
|
auto r = or(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that or(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0X33333333 ;
|
|
auto z = makeBig( 0x01234567, 0xBBBBFFFF );
|
|
auto r = or(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0XCCCCCCCC ;
|
|
auto z = makeBig( 0xCDEFCDEF );
|
|
auto r = or(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that xor(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333, 0X33333333 );
|
|
auto z = makeBig( 0x32107654, 0xBA98FEDC );
|
|
auto r = xor(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0X33333333 );
|
|
auto z = makeBig( 0x01234567, 0xBA98FEDC );
|
|
auto r = xor(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = makeBig( 0XCCCCCCCC );
|
|
auto z = makeBig( 0xFEDCBA98, 0x45670123 );
|
|
auto r = xor(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that xor(Big,int) works
|
|
{
|
|
auto x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
auto y = 0X33333333 ;
|
|
auto z = makeBig( 0x01234567, 0xBA98FEDC );
|
|
auto r = xor(x,y);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that shl(Big,uint) works
|
|
{
|
|
Big x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
Big z = makeBig( 0x00000123, 0x456789AB, 0xCDEF0000 );
|
|
Big r = shl(x,16);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that shlDigits(Big,uint) works
|
|
{
|
|
Big x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
Big z = makeBig( 0x01234567, 0x89ABCDEF, 0x00000000, 0x00000000 );
|
|
Big r = shlDigits(x,2);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that shr(Big,uint) works
|
|
{
|
|
Big x = makeBig( 0x00000123, 0x456789AB, 0xCDEF4444 );
|
|
Big z = makeBig( 0x12345678, 0x9ABCDEF4 );
|
|
auto t = shr(x,12);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r == 0x00000444, format("remainder = %08X",t.r));
|
|
}{
|
|
auto x = makeBig( 0x80000000, 0x00000000 );
|
|
auto z = makeBig( 0xFFFF8000, 0x00000000 );
|
|
auto t = shr(x,16);
|
|
assert(t.q.digits == z.digits, hex(t.q));
|
|
assert(t.r == 0x00000000, format("remainder = %08X",t.r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that shrDigits(Big,uint) works
|
|
{
|
|
Big x = makeBig( 0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210 );
|
|
Big z = makeBig( 0x01234567, 0x89ABCDEF );
|
|
Big r = shrDigits(x,2);
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that cmp(Big,Big) works
|
|
{
|
|
Big x = makeBig( 0x11111111, 0x11111111, 0x11111111 );
|
|
Big y = makeBig( 0x11111111, 0x11111111 );
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0x11111111, 0x11111111 );
|
|
Big y = makeBig( 0x11111111, 0x11111111, 0x11111111 );
|
|
assert(cmp(x,y) < 0);
|
|
}{
|
|
Big x = makeBig( 0xEEEEEEEE, 0xEEEEEEEE, 0xEEEEEEEE );
|
|
Big y = makeBig( 0xEEEEEEEE, 0xEEEEEEEE );
|
|
assert(cmp(x,y) < 0);
|
|
}{
|
|
Big x = makeBig( 0xEEEEEEEE, 0xEEEEEEEE );
|
|
Big y = makeBig( 0xEEEEEEEE, 0xEEEEEEEE, 0xEEEEEEEE );
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0x33333333, 0x22222222, 0xEEEEEEEE );
|
|
Big y = makeBig( 0x33333333, 0x11111111, 0xEEEEEEEE );
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0x33333333, 0x11111111, 0xEEEEEEEE );
|
|
Big y = makeBig( 0x33333333, 0x22222222, 0xEEEEEEEE );
|
|
assert(cmp(x,y) < 0);
|
|
}{
|
|
Big x = makeBig( 0x33333333, 0x11111111, 0xEEEEEEEE );
|
|
Big y = makeBig( 0xEEEEEEEE, 0x22222222, 0xEEEEEEEE );
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0x01234567, 0x88888888, 0x76543210 );
|
|
Big y = makeBig( 0x01234567, 0x88888888, 0x76543210 );
|
|
assert(cmp(x,y) == 0);
|
|
}
|
|
|
|
// This block of unittests demonstrates that cmp(Big,uint) works
|
|
{
|
|
Big x = makeBig( 0x11111111, 0x11111111, 0x11111111 );
|
|
Digit y = 0x11111111 ;
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0xEEEEEEEE, 0xEEEEEEEE, 0xEEEEEEEE );
|
|
Digit y = 0xEEEEEEEE ;
|
|
assert(cmp(x,y) < 0);
|
|
}{
|
|
Big x = makeBig( 0x22222222 );
|
|
Digit y = 0x11111111 ;
|
|
assert(cmp(x,y) > 0);
|
|
}{
|
|
Big x = makeBig( 0x11111111 );
|
|
Digit y = 0x22222222 ;
|
|
assert(cmp(x,y) < 0);
|
|
}{
|
|
Big x = makeBig( 0x76543210 );
|
|
Digit y = 0x76543210 ;
|
|
assert(cmp(x,y) == 0);
|
|
}
|
|
|
|
// This block of unittests demonstrates that fromString(string) works
|
|
{
|
|
Big r = fromString("123");
|
|
Big z = makeBig( 0x0000007B );
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
Big r = fromString("12_345_678_901_234_567_890");
|
|
Big z = makeBig( 0x00000000, 0xAB54A98C, 0xEB1F0AD2 );
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
Big r = fromString("-12_345_678_901_234_567_890");
|
|
Big z = makeBig( 0xFFFFFFFF, 0x54AB5673, 0x14E0F52E );
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
Big r = fromString("0x0123_4567_89AB_CDEF");
|
|
Big z = makeBig( 0x01234567, 0x89ABCDEF );
|
|
assert(r.digits == z.digits, hex(r));
|
|
}{
|
|
Big r = fromString("-0x0123_4567_89AB_CDEF");
|
|
Big z = makeBig( 0xFEDCBA98, 0x76543211 );
|
|
assert(r.digits == z.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that decimal(Big) works
|
|
{
|
|
Big x = makeBig( 0x0000007B );
|
|
string r = decimal(x);
|
|
assert(r == "123", r);
|
|
}{
|
|
Big x = makeBig( 0x00000000, 0xAB54A98C, 0xEB1F0AD2 );
|
|
string r = decimal(x);
|
|
assert(r == "12345678901234567890", r);
|
|
}{
|
|
Big x = makeBig( 0xFFFFFFFF, 0x54AB5673, 0x14E0F52E );
|
|
string r = decimal(x);
|
|
assert(r == "-12345678901234567890", r);
|
|
}{
|
|
Big x = makeBig( 0x01234567, 0x89ABCDEF );
|
|
string r = decimal(x);
|
|
assert(r == "81985529216486895", r);
|
|
}{
|
|
Big x = makeBig( 0xFEDCBA98, 0x76543211 );
|
|
string r = decimal(x);
|
|
assert(r == "-81985529216486895", r);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opAssign works
|
|
{
|
|
Big z = makeBig( 0x00000064 );
|
|
Big r;
|
|
r.opAssign(z);
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r.opAssign( cast(int)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r.opAssign( cast(uint)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r.opAssign( cast(long)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r.opAssign( cast(ulong)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r.opAssign( "100" );
|
|
assert(z.digits == r.digits, hex(r));
|
|
}{
|
|
Big r;
|
|
r.opAssign( cast(long)0xFEDCBA9876543210 );
|
|
Big z = makeBig( 0xFEDCBA98, 0x76543210 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
}{
|
|
Big r;
|
|
r.opAssign( cast(ulong)0xFEDCBA9876543210 );
|
|
Big z = makeBig( 0x00000000, 0xFEDCBA98, 0x76543210 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
|
|
}
|
|
|
|
// This block of unittests demonstrates that static opCall works
|
|
{
|
|
Big z = makeBig( 0x00000064 );
|
|
Big r = BigInt(z);
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r = BigInt( cast(int)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r = BigInt( cast(uint)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r = BigInt( cast(long)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r = BigInt( cast(ulong)100 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
r = BigInt( "100" );
|
|
assert(z.digits == r.digits, hex(r));
|
|
}{
|
|
Big r = BigInt( cast(long)0xFEDCBA9876543210 );
|
|
Big z = makeBig( 0xFEDCBA98, 0x76543210 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
}{
|
|
Big r = BigInt( cast(ulong)0xFEDCBA9876543210 );
|
|
Big z = makeBig( 0x00000000, 0xFEDCBA98, 0x76543210 );
|
|
assert(z.digits == r.digits, hex(r));
|
|
}
|
|
|
|
// This block of unittests demonstrates that castTo works
|
|
{
|
|
BigInt z = makeBig( 0x00000000, 0x89ABCDEF, 0x89ABCDEF );
|
|
BigInt r;
|
|
z.castTo(r);
|
|
assert(z.digits == r.digits, hex(r));
|
|
//
|
|
int i;
|
|
z.castTo(i);
|
|
assert(i == -1985229329);
|
|
//
|
|
uint j;
|
|
z.castTo(j);
|
|
assert(j == 2309737967);
|
|
//
|
|
long k;
|
|
z.castTo(k);
|
|
assert(k == -8526495040805286417);
|
|
//
|
|
ulong l;
|
|
z.castTo(l);
|
|
assert(l == 9920249032904265199u);
|
|
//
|
|
string s;
|
|
z.castTo(s);
|
|
assert(s == "9920249032904265199");
|
|
}
|
|
|
|
// This block of unittests demonstrates that opEquals and opCmp work
|
|
{
|
|
BigInt x = makeBig( 0x00000000, 0x89ABCDEF, 0x89ABCDEF );
|
|
assert(x > BigInt("9920249032904265198"));
|
|
assert(x == BigInt("9920249032904265199"));
|
|
assert(x < BigInt("9920249032904265200"));
|
|
//
|
|
assert(x.opEquals(BigInt("9920249032904265199")));
|
|
assert(x.opCmp(BigInt("9920249032904265199") == 0));
|
|
//
|
|
BigInt y = 42;
|
|
assert(y > 41);
|
|
assert(y == 42);
|
|
assert(y < 43);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opNeg works
|
|
{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = "-100000000000000";
|
|
assert(x == -y);
|
|
assert(-x == y);
|
|
assert(x == -(-x));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opPos works
|
|
{
|
|
BigInt x = "100000000000000";
|
|
assert(x == +x);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opCom works
|
|
{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = "-100000000000001";
|
|
assert(x == ~y);
|
|
assert(~x == y);
|
|
assert(x == ~(~x));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opPostInc and opPostDec work
|
|
{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x++;
|
|
assert(y == BigInt("100000000000000"));
|
|
assert(x == BigInt("100000000000001"));
|
|
}{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x--;
|
|
assert(y == BigInt("100000000000000"));
|
|
assert(x == BigInt( "99999999999999"));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opAdd works
|
|
{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x + 42;
|
|
assert(y == BigInt("100000000000042"));
|
|
BigInt z = x + x;
|
|
assert(z == BigInt("200000000000000"));
|
|
}{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x + -42;
|
|
assert(y == BigInt("99999999999958"));
|
|
BigInt z = x + -(x + x);
|
|
assert(z == BigInt("-100000000000000"));
|
|
}{
|
|
BigInt x = "100000000000000";
|
|
x += 42;
|
|
assert(x == BigInt("100000000000042"));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opSub works
|
|
{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x - 42;
|
|
assert(y == BigInt("99999999999958"));
|
|
BigInt z = x - x;
|
|
assert(z == BigInt.init);
|
|
}{
|
|
BigInt x = "100000000000000";
|
|
BigInt y = x - -42;
|
|
assert(y == BigInt("100000000000042"));
|
|
BigInt z = x - -(x + x);
|
|
assert(z == BigInt("300000000000000"));
|
|
}{
|
|
BigInt x = "100000000000000";
|
|
x -= 42;
|
|
assert(x == BigInt("99999999999958"));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opMul works
|
|
{
|
|
BigInt a = "9588669891916142";
|
|
BigInt b = "7452469135154800";
|
|
auto c = a * b;
|
|
assert(c == "71459266416693160362545788781600");
|
|
}{
|
|
BigInt a = "-9588669891916142";
|
|
BigInt b = "7452469135154800";
|
|
auto c = a * b;
|
|
assert(c == "-71459266416693160362545788781600");
|
|
}{
|
|
BigInt a = "9588669891916142";
|
|
BigInt b = "-7452469135154800";
|
|
auto c = a * b;
|
|
assert(c == "-71459266416693160362545788781600");
|
|
}{
|
|
BigInt a = "-9588669891916142";
|
|
BigInt b = "-7452469135154800";
|
|
auto c = a * b;
|
|
assert(c == "71459266416693160362545788781600");
|
|
}{
|
|
BigInt a = "10000000000000000000";
|
|
a *= -4;
|
|
assert(a == "-40000000000000000000");
|
|
}
|
|
|
|
// This block of unittests demonstrates that opDiv works
|
|
{
|
|
BigInt a = "10000000000000000";
|
|
BigInt b = "7";
|
|
auto c = a / b;
|
|
assert(c == "1428571428571428");
|
|
}{
|
|
BigInt a = "-10000000000000000";
|
|
BigInt b = "7";
|
|
auto c = a / b;
|
|
assert(c == "-1428571428571428");
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
BigInt b = "-7";
|
|
auto c = a / b;
|
|
assert(c == "-1428571428571428");
|
|
}{
|
|
BigInt a = "-10000000000000000";
|
|
BigInt b = "-7";
|
|
auto c = a / b;
|
|
assert(c == "1428571428571428");
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
a /= -7;
|
|
assert(a == "-1428571428571428");
|
|
}
|
|
|
|
// This block of unittests demonstrates that opMod works
|
|
{
|
|
BigInt a = "10000000000000000";
|
|
BigInt b = "7";
|
|
auto c = a % b;
|
|
assert(c == 4);
|
|
}{
|
|
BigInt a = "-10000000000000000";
|
|
BigInt b = "7";
|
|
auto c = a % b;
|
|
assert(c == -4);
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
BigInt b = "-7";
|
|
auto c = a % b;
|
|
assert(c == 4);
|
|
}{
|
|
BigInt a = "-10000000000000000";
|
|
BigInt b = "-7";
|
|
auto c = a % b;
|
|
assert(c == -4);
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
a %= -7;
|
|
assert(a == 4);
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
a %= BigInt("0x80000000");
|
|
}{
|
|
BigInt a = "10000000000000000";
|
|
int i = 0x80000000;
|
|
a %= i;
|
|
}
|
|
|
|
// This block of unittests demonstrates that opAnd works
|
|
{
|
|
BigInt x = "0xCCCCCCCC";
|
|
auto y = x & 0xAAAAAAAA;
|
|
assert(y == 0x88888888);
|
|
static assert(is(typeof(y) == uint));
|
|
}{
|
|
BigInt x = "0xCCCCCCCC";
|
|
x &= 0xAAAAAAAA;
|
|
assert(x == 0x88888888);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opOr works
|
|
{
|
|
BigInt x = "0xCCCCCCCC";
|
|
auto y = x | 0xAAAAAAAA;
|
|
assert(y == 0xEEEEEEEE);
|
|
}{
|
|
BigInt x = "0xCCCCCCCC";
|
|
x |= 0xAAAAAAAA;
|
|
assert(x == 0xEEEEEEEE);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opXor works
|
|
{
|
|
BigInt x = "0xCCCCCCCC";
|
|
auto y = x ^ 0xAAAAAAAA;
|
|
assert(y == 0x66666666);
|
|
}{
|
|
BigInt x = "0xCCCCCCCC";
|
|
x ^= 0xAAAAAAAA;
|
|
assert(x == 0x66666666);
|
|
}
|
|
|
|
// This block of unittests demonstrates that opShl works
|
|
{
|
|
BigInt x = "0x1234567";
|
|
BigInt y = x << 80;
|
|
assert(y == BigInt("0x123456700000000000000000000"));
|
|
}{
|
|
BigInt x = "0x1234567";
|
|
x <<= 80;
|
|
assert(x == BigInt("0x123456700000000000000000000"));
|
|
}
|
|
|
|
// This block of unittests demonstrates that opShr works
|
|
{
|
|
BigInt x = "0x1234567FFFFFFFFFFFFFFFFFFFF";
|
|
BigInt y = x >> 80;
|
|
assert(y == BigInt("0x1234567"));
|
|
}{
|
|
BigInt x = "0x1234567FFFFFFFFFFFFFFFFFFFF";
|
|
x >>= 80;
|
|
assert(x == BigInt("0x1234567"));
|
|
}
|
|
|
|
// This block of unittests demonstrates that toString works
|
|
{
|
|
string s = "128649024696729866742487649";
|
|
BigInt x = s;
|
|
string t = x.toString;
|
|
assert(t == s);
|
|
}
|
|
|
|
// This block of unittests demonstrates that sgn and abs work
|
|
{
|
|
BigInt x = 1000;
|
|
assert(x.sgn == 1);
|
|
assert(x.abs == 1000);
|
|
}{
|
|
BigInt x = -1000;
|
|
assert(x.sgn == -1);
|
|
assert(x.abs == 1000);
|
|
}{
|
|
BigInt x = 0;
|
|
assert(x.sgn == 0);
|
|
assert(x.abs == 0);
|
|
}
|
|
|
|
// Silly ad hoc test
|
|
{
|
|
BigInt a = "9588669891916142";
|
|
BigInt b = "7452469135154800";
|
|
auto c = a * b; // c = a.b
|
|
assert(c == "71459266416693160362545788781600");
|
|
auto d = b * a; // d = a.b
|
|
assert(d == "71459266416693160362545788781600");
|
|
assert(d == c);
|
|
d = c * "794628672112"; // d = 794628672112.a.b
|
|
assert(d == "56783581982794522489042432639320434378739200");
|
|
auto e = c + d; // e = 794628672113.a.b
|
|
assert(e == "56783581982865981755459125799682980167520800");
|
|
auto f = d + c; // f = 794628672113.a.b
|
|
assert(f == e);
|
|
auto g = f - c; // g = 794628672112.a.b
|
|
assert(g == d);
|
|
g = f - d; // g = a.b
|
|
assert(g == c);
|
|
e = 12345678; // e = 12345678
|
|
g = c + e; // g = a.b + e
|
|
auto h = g / b; // h = a
|
|
auto i = g % b; // i = e
|
|
assert(h == a);
|
|
assert(i == e);
|
|
}
|
|
|
|
}
|