mirror of
https://github.com/dlang/phobos.git
synced 2025-05-11 23:05:34 +03:00
Merge pull request #1721 from Biotronic/master
Fix 8167 (BigInt identity constructor) and 9061 (BigInt bitwise ops)
This commit is contained in:
commit
05738e116c
2 changed files with 106 additions and 8 deletions
58
std/bigint.d
58
std/bigint.d
|
@ -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;
|
||||
|
|
|
@ -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, '_');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue