Merge pull request #1721 from Biotronic/master

Fix 8167 (BigInt identity constructor) and 9061 (BigInt bitwise ops)
This commit is contained in:
monarch dodra 2013-12-17 06:06:26 -08:00
commit 05738e116c
2 changed files with 106 additions and 8 deletions

View file

@ -32,7 +32,7 @@ private import std.traits;
/** A struct representing an arbitrary precision integer
*
* All arithmetic operations are supported, except
* unsigned shift right (>>>). Logical operations are not currently supported.
* unsigned shift right (>>>). Bitwise operations (|, &, ^, ~) are supported, and behave as if BigInt was an infinite length 2's complement number.
*
* BigInt implements value semantics using copy-on-write. This means that
* assignment is cheap, but operations such as x++ will cause heap
@ -111,6 +111,12 @@ public:
data = data.init; // @@@: Workaround for compiler bug
opAssign(x);
}
///
this(T)(T x) pure if (is(Unqual!T == BigInt))
{
opAssign(x);
}
///
BigInt opAssign(T)(T x) pure if (isIntegral!T)
@ -131,7 +137,7 @@ public:
// BigInt op= integer
BigInt opOpAssign(string op, T)(T y) pure
if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
|| op==">>" || op=="<<" || op=="^^") && isIntegral!T)
|| op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T)
{
ulong u = absUnsign(y);
@ -196,13 +202,18 @@ public:
sign = (y & 1) ? sign : false;
data = BigUint.pow(data, u);
}
else static if (op=="|" || op=="&" || op=="^")
{
BigInt b = y;
opOpAssign!op(b);
}
else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported");
return this;
}
// BigInt op= BigInt
BigInt opOpAssign(string op, T)(T y) pure
if ((op=="+" || op== "-" || op=="*" || op=="/" || op=="%")
if ((op=="+" || op== "-" || op=="*" || op=="/" || op=="%" || op=="|" || op=="&" || op=="^")
&& is (T: BigInt))
{
static if (op == "+")
@ -238,13 +249,17 @@ public:
sign = false;
}
}
else static if (op == "|" || op == "&" || op == "^")
{
data = BigUint.bitwiseOp!op(data, y.data, sign, y.sign, sign);
}
else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported");
return this;
}
// BigInt op BigInt
BigInt opBinary(string op, T)(T y) pure const
if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="%")
if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="%" || op=="|" || op=="&" || op=="^")
&& is (T: BigInt))
{
BigInt r = this;
@ -253,7 +268,7 @@ public:
// BigInt op integer
BigInt opBinary(string op, T)(T y) pure const
if ((op=="+" || op == "*" || op=="-" || op=="/"
if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="|" || op=="&" || op=="^"
|| op==">>" || op=="<<" || op=="^^") && isIntegral!T)
{
BigInt r = this;
@ -274,7 +289,7 @@ public:
// Commutative operators
BigInt opBinaryRight(string op, T)(T y) pure const
if ((op=="+" || op=="*") && isIntegral!T)
if ((op=="+" || op=="*" || op=="|" || op=="&" || op=="^") && isIntegral!T)
{
return opBinary!(op)(y);
}
@ -318,7 +333,7 @@ public:
}
}
// const unary operations
BigInt opUnary(string op)() pure const if (op=="+" || op=="-")
BigInt opUnary(string op)() pure const if (op=="+" || op=="-" || op=="~")
{
static if (op=="-")
{
@ -326,6 +341,10 @@ public:
r.negate();
return r;
}
else static if (op=="~")
{
return -(this+1);
}
else static if (op=="+")
return this;
}
@ -879,6 +898,31 @@ unittest // 11148
n *= 2;
}
unittest // 8167
{
BigInt a = BigInt(3);
BigInt b = BigInt(a);
}
unittest // 9061
{
long l1 = 0x12345678_90ABCDEF;
long l2 = 0xFEDCBA09_87654321;
long l3 = l1 | l2;
long l4 = l1 & l2;
long l5 = l1 ^ l2;
BigInt b1 = l1;
BigInt b2 = l2;
BigInt b3 = b1 | b2;
BigInt b4 = b1 & b2;
BigInt b5 = b1 ^ b2;
assert(l3 == b3);
assert(l4 == b4);
assert(l5 == b5);
}
unittest // 11600
{
import std.conv;

View file

@ -639,6 +639,26 @@ public:
divModInternal(result, rem, x.data, y.data);
return BigUint(removeLeadingZeros(assumeUnique(rem)));
}
// return x op y
static BigUint bitwiseOp(string op)(BigUint x, BigUint y, bool xSign, bool ySign, ref bool resultSign) pure if (op == "|" || op == "^" || op == "&")
{
auto d1 = includeSign(x.data, y.uintLength, xSign);
auto d2 = includeSign(y.data, x.uintLength, ySign);
foreach (i; 0..d1.length)
{
mixin("d1[i] " ~ op ~ "= d2[i];");
}
mixin("resultSign = xSign " ~ op ~ " ySign;");
if (resultSign) {
twosComplement(d1, d1);
}
return BigUint(removeLeadingZeros(assumeUnique(d1)));
}
/**
* Return a BigUint which is x raised to the power of y.
@ -947,6 +967,41 @@ unittest
private:
void twosComplement(const(BigDigit) [] x, BigDigit[] result) pure
{
foreach (i; 0..x.length)
{
result[i] = ~x[i];
}
result[x.length..$] = BigDigit.max;
bool sgn = false;
foreach (i; 0..result.length) {
if (result[i] == BigDigit.max) {
result[i] = 0;
} else {
result[i] += 1;
break;
}
}
}
// Encode BigInt as BigDigit array (sign and 2's complement)
BigDigit[] includeSign(const(BigDigit) [] x, size_t minSize, bool sign) pure
{
size_t length = (x.length > minSize) ? x.length : minSize;
BigDigit [] result = new BigDigit[length];
if (sign)
{
twosComplement(x, result);
}
else
{
result[0..x.length] = x;
}
return result;
}
// works for any type
T intpow(T)(T x, ulong n) pure
@ -2244,7 +2299,6 @@ version(unittest)
unittest
{
void printBiguint(const uint [] data)
{
char [] buff = biguintToHex(new char[data.length*9], data, '_');