Skip to content

Commit

Permalink
tentatively impl in BigInt
Browse files Browse the repository at this point in the history
  • Loading branch information
ellie-idb committed Dec 29, 2021
1 parent c20327a commit d7ffe9c
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 36 deletions.
1 change: 1 addition & 0 deletions source/mir/bignum/fixed.d
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ struct UInt(size_t size)
unsigned remainder value
+/
auto divRem(size_t rhsSize)(UInt!rhsSize rhs)
@safe pure nothrow @nogc scope
{
import mir.bignum.low_level_view : divm, BigUIntView;

Expand Down
178 changes: 142 additions & 36 deletions source/mir/bignum/integer.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct BigInt(size_t maxSize64)
///
bool sign;
///
uint length;
ulong length;
///
size_t[ulong.sizeof / size_t.sizeof * maxSize64] data = void;

Expand Down Expand Up @@ -317,36 +317,113 @@ struct BigInt(size_t maxSize64)
return overflow;
}

/++
Performs division & extracts the remainder.
Params:
rhs = unsigned value to divide by
Returns:
unsigned remainder value
+/
auto divRem(size_t rhsSize)(UInt!rhsSize rhs)
@safe pure nothrow @nogc scope
{
import mir.bignum.low_level_view : divm, BigUIntView;

enum m = ((data.length * (size_t.sizeof * 8)) / (uint.sizeof * 8)), n = (rhsSize / (uint.sizeof * 8));

struct QuotientAndRemainder
{
// XXX: we have to assume the quotient size here,
// checking at runtime would be more accurate for better space savings
UInt!(data.length * (size_t.sizeof * 8)) quotient;
UInt!rhsSize remainder;
}

QuotientAndRemainder val;

uint[m + 1] _div;
// shouldn't be unaligned here -- maybe a possibility though
_div[0 .. $ - 1] = (cast(uint[])data)[0 .. $];

BigUIntView!uint dividend = BigUIntView!uint(_div);
BigUIntView!uint divisor = cast(BigUIntView!uint)rhs.view;
BigUIntView!uint quotient = cast(BigUIntView!uint)val.quotient.view;
divm(dividend, divisor, quotient);

BigUIntView!uint remainder = cast(BigUIntView!uint)val.remainder.view;
remainder.coefficients[0 .. $] = (cast(uint[])_div)[0 .. remainder.coefficients.length];

return val;
}

/++
Performs `big /= rhs` operation.
Params:
rhs = unsigned value to divide by
Returns:
quotient from division
+/
UInt!size opOpAssign(string op : "/", size_t size)(UInt!size rhs)
@safe pure nothrow @nogc
ref opOpAssign(string op : "/", size_t size)(UInt!size rhs)
@safe pure nothrow @nogc return
{
UInt!size rem = 0;
if (length)
{
uint[(maxSize64 * 2) + 1] buffer = void;
buffer[0 .. $ - 1] = (cast(uint[])data)[0 .. $];
buffer[$ - 1] = 0;
data[0 .. $] = 0;

BigUIntView!uint dividend = BigUIntView!uint(buffer);
BigUIntView!uint divisor = cast(BigUIntView!uint)rhs.view;
BigUIntView!uint quotient = cast(BigUIntView!uint)view.unsigned;
BigUIntView!uint remainder = cast(BigUIntView!uint)rem.view;
divm(dividend, divisor, quotient);

// This is a safe copy, because our remainder is guaranteed to be AT MOST n bytes
// where n is the size of the right-hand side.
remainder.coefficients[0 .. $] = (cast(uint[])buffer)[0 .. remainder.coefficients.length];
normalize;
auto result = divRem(rhs);
data = result.quotient.data;
// XXX: I hate this. Is there a better solution here?
length = result.quotient.view.normalized.coefficients.length;
}
return this;
}


ref opOpAssign(string op : "/")(ulong rhs)
@safe pure nothrow @nogc return
{
if (length)
{
auto result = divRem(UInt!64(rhs));
data = result.quotient.data;
// XXX: same as above
length = result.quotient.view.normalized.coefficients.length;
}
return this;
}


/++
Performs `big %= rhs` operation.
Params:
rhs = unsigned value to divide by
Returns:
remainder from division
+/
ref opOpAssign(string op : "%", size_t size)(UInt!size rhs)
@safe pure nothrow @nogc return
{
if (length)
{
auto result = divRem(rhs);
data = 0;
data[0 .. result.remainder.data.length] = result.remainder.data;
// XXX: same as above
length = result.remainder.view.normalized.coefficients.length;
}
return rem;
return this;
}

ref opOpAssign(string op : "%")(ulong rhs)
@safe pure nothrow @nogc return
{
if (length)
{
auto result = divRem(UInt!64(rhs));
data = 0;
data[0 .. result.remainder.data.length] = result.remainder.data;
// XXX: same as above
length = result.remainder.view.normalized.coefficients.length;
}
return this;
}

/++
Expand Down Expand Up @@ -396,6 +473,29 @@ struct BigInt(size_t maxSize64)
return overflow;
}

template opBinary(string op)
if (op == "/" || op == "%")
{
///
BigInt opBinary(size_t size)(UInt!size rhs)
const @safe pure nothrow @nogc
if (size <= maxSize64 * (size_t.sizeof * 8))
{
BigInt ret = this;
ret.opOpAssign!op(rhs);
return ret;
}

/// ditto
BigInt opBinary(ulong rhs)
const @safe pure nothrow @nogc
{
BigInt ret = this;
ret.opOpAssign!op(rhs);
return ret;
}
}

/++
+/
static BigInt fromHexString(bool allowUnderscores = false)(scope const(char)[] str)
Expand Down Expand Up @@ -687,35 +787,41 @@ unittest
import mir.bignum.low_level_view;

{
auto b = BigInt!4.fromHexString("c39b18a9f06fd8e962d99935cea0707f79a222050aaeaaaed17feb7aa76999d7");
auto a = BigInt!4.fromHexString("c39b18a9f06fd8e962d99935cea0707f79a222050aaeaaaed17feb7aa76999d7");
auto b = UInt!128.fromHexString("f79a222050aaeaaa417fa25a2ac93291");

auto rem = b /= UInt!128.fromHexString("f79a222050aaeaaa417fa25a2ac93291");
assert(b == BigInt!4.fromHexString("ca3d7e25aebe687b7cc1b250b44690fb"));
assert(rem == UInt!128.fromHexString("bf4c87424431d21563f23b1fc00d75ac"));
debug {
import std.stdio;
auto result = a / b;
writefln("%s %s", result.data, BigInt!4.fromHexString("ca3d7e25aebe687b7cc1b250b44690fb").data);
writefln("%s", result);
}
assert(a / b == BigInt!4.fromHexString("ca3d7e25aebe687b7cc1b250b44690fb"));
assert(a % b == BigInt!4.fromHexString("bf4c87424431d21563f23b1fc00d75ac"));
}

{
auto d = BigInt!4.fromHexString("7fff000080000000000000000000");
auto a = BigInt!4.fromHexString("7fff000080000000000000000000");
auto b = UInt!128.fromHexString("80000000000000000001");

auto rem = d /= UInt!128.fromHexString("80000000000000000001");
assert(d == BigInt!4.fromHexString("fffe0000"));
assert(rem == UInt!128.fromHexString("7fffffffffff00020000"));
assert(a / b == BigInt!4.fromHexString("fffe0000"));
assert(a % b == BigInt!4.fromHexString("7fffffffffff00020000"));
}

{
auto d = BigInt!16.fromHexString("76d053cdcc87ec8c9455c375d6a08c799fad73cf07415e70af5dfacaff4bd306647a7cceb98839cce89ae65900938821564fd2af3c9d881c172264bb17e3530ce79b938d5eb7ffec558be43ab5b684978417c5053fb8df63fc65c9efd8b2e86469c53259509eb597f81647930f24ef05a79bfecf04e5ec52414c6a3f7481d533");
auto a = BigInt!16.fromHexString("76d053cdcc87ec8c9455c375d6a08c799fad73cf07415e70af5dfacaff4bd306647a7cceb98839cce89ae65900938821564fd2af3c9d881c172264bb17e3530ce79b938d5eb7ffec558be43ab5b684978417c5053fb8df63fc65c9efd8b2e86469c53259509eb597f81647930f24ef05a79bfecf04e5ec52414c6a3f7481d533");
auto b = UInt!128.fromHexString("9c5c1aa6ad7ad18065a3a74598e27bee");

auto rem = d /= UInt!128.fromHexString("9c5c1aa6ad7ad18065a3a74598e27bee");
assert(d == BigInt!16.fromHexString("c2871f2b07522bda1e63de12850d2208bb242c716b5739d6744ee1d9c937b8d765d3742e18785d08c2405e5c83f3c875d5726d09dfaee29e813675a4f91bfee01e8cbbbca9588325d54cf2a625faffde4d8709e0517f786f609d8ce6997e0e71d2f976ae169b0c4be7a7dba3135af96c"));
assert(rem == UInt!128.fromHexString("85d81587a8b62af1874315d26ebf0ecb"));
assert(a / b == BigInt!16.fromHexString("c2871f2b07522bda1e63de12850d2208bb242c716b5739d6744ee1d9c937b8d765d3742e18785d08c2405e5c83f3c875d5726d09dfaee29e813675a4f91bfee01e8cbbbca9588325d54cf2a625faffde4d8709e0517f786f609d8ce6997e0e71d2f976ae169b0c4be7a7dba3135af96c"));
assert(a % b == BigInt!16.fromHexString("85d81587a8b62af1874315d26ebf0ecb"));
}

{
auto d = BigInt!4.fromHexString("DEADBEEF");
auto a = BigInt!4.fromHexString("DEADBEEF");
auto b = UInt!256.fromHexString("18aeff9fa4aace484a9f8f9002cdf38fa6e53fc0f6c035051dc86931c1c08316");

auto rem = d /= UInt!256.fromHexString("18aeff9fa4aace484a9f8f9002cdf38fa6e53fc0f6c035051dc86931c1c08316");
assert(d == 0);
assert(rem == 0xDEADBEEF);
assert(a / b == 0);
assert(a % b == 0xDEADBEEF);
}

}
Expand Down

0 comments on commit d7ffe9c

Please sign in to comment.