mirror of
https://github.com/dlang/phobos.git
synced 2025-05-14 00:46:22 +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
|
/** A struct representing an arbitrary precision integer
|
||||||
*
|
*
|
||||||
* All arithmetic operations are supported, except
|
* 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
|
* BigInt implements value semantics using copy-on-write. This means that
|
||||||
* assignment is cheap, but operations such as x++ will cause heap
|
* assignment is cheap, but operations such as x++ will cause heap
|
||||||
|
@ -112,6 +112,12 @@ public:
|
||||||
opAssign(x);
|
opAssign(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
this(T)(T x) pure if (is(Unqual!T == BigInt))
|
||||||
|
{
|
||||||
|
opAssign(x);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
BigInt opAssign(T)(T x) pure if (isIntegral!T)
|
BigInt opAssign(T)(T x) pure if (isIntegral!T)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +137,7 @@ public:
|
||||||
// BigInt op= integer
|
// BigInt op= integer
|
||||||
BigInt opOpAssign(string op, T)(T y) pure
|
BigInt opOpAssign(string op, T)(T y) pure
|
||||||
if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
|
if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
|
||||||
|| op==">>" || op=="<<" || op=="^^") && isIntegral!T)
|
|| op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T)
|
||||||
{
|
{
|
||||||
ulong u = absUnsign(y);
|
ulong u = absUnsign(y);
|
||||||
|
|
||||||
|
@ -196,13 +202,18 @@ public:
|
||||||
sign = (y & 1) ? sign : false;
|
sign = (y & 1) ? sign : false;
|
||||||
data = BigUint.pow(data, u);
|
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");
|
else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BigInt op= BigInt
|
// BigInt op= BigInt
|
||||||
BigInt opOpAssign(string op, T)(T y) pure
|
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))
|
&& is (T: BigInt))
|
||||||
{
|
{
|
||||||
static if (op == "+")
|
static if (op == "+")
|
||||||
|
@ -238,13 +249,17 @@ public:
|
||||||
sign = false;
|
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");
|
else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BigInt op BigInt
|
// BigInt op BigInt
|
||||||
BigInt opBinary(string op, T)(T y) pure const
|
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))
|
&& is (T: BigInt))
|
||||||
{
|
{
|
||||||
BigInt r = this;
|
BigInt r = this;
|
||||||
|
@ -253,7 +268,7 @@ public:
|
||||||
|
|
||||||
// BigInt op integer
|
// BigInt op integer
|
||||||
BigInt opBinary(string op, T)(T y) pure const
|
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)
|
|| op==">>" || op=="<<" || op=="^^") && isIntegral!T)
|
||||||
{
|
{
|
||||||
BigInt r = this;
|
BigInt r = this;
|
||||||
|
@ -274,7 +289,7 @@ public:
|
||||||
|
|
||||||
// Commutative operators
|
// Commutative operators
|
||||||
BigInt opBinaryRight(string op, T)(T y) pure const
|
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);
|
return opBinary!(op)(y);
|
||||||
}
|
}
|
||||||
|
@ -318,7 +333,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// const unary operations
|
// 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=="-")
|
static if (op=="-")
|
||||||
{
|
{
|
||||||
|
@ -326,6 +341,10 @@ public:
|
||||||
r.negate();
|
r.negate();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
else static if (op=="~")
|
||||||
|
{
|
||||||
|
return -(this+1);
|
||||||
|
}
|
||||||
else static if (op=="+")
|
else static if (op=="+")
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -879,6 +898,31 @@ unittest // 11148
|
||||||
n *= 2;
|
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
|
unittest // 11600
|
||||||
{
|
{
|
||||||
import std.conv;
|
import std.conv;
|
||||||
|
|
|
@ -640,6 +640,26 @@ public:
|
||||||
return BigUint(removeLeadingZeros(assumeUnique(rem)));
|
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.
|
* Return a BigUint which is x raised to the power of y.
|
||||||
* Method: Powers of 2 are removed from x, then left-to-right binary
|
* Method: Powers of 2 are removed from x, then left-to-right binary
|
||||||
|
@ -947,6 +967,41 @@ unittest
|
||||||
|
|
||||||
|
|
||||||
private:
|
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
|
// works for any type
|
||||||
T intpow(T)(T x, ulong n) pure
|
T intpow(T)(T x, ulong n) pure
|
||||||
|
@ -2244,7 +2299,6 @@ version(unittest)
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
|
|
||||||
void printBiguint(const uint [] data)
|
void printBiguint(const uint [] data)
|
||||||
{
|
{
|
||||||
char [] buff = biguintToHex(new char[data.length*9], data, '_');
|
char [] buff = biguintToHex(new char[data.length*9], data, '_');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue