From d7ffe9ccc70809067da88f8b7111be877d713cec Mon Sep 17 00:00:00 2001 From: hatf0 Date: Wed, 29 Dec 2021 14:36:15 -0500 Subject: [PATCH] tentatively impl in BigInt --- source/mir/bignum/fixed.d | 1 + source/mir/bignum/integer.d | 178 ++++++++++++++++++++++++++++-------- 2 files changed, 143 insertions(+), 36 deletions(-) diff --git a/source/mir/bignum/fixed.d b/source/mir/bignum/fixed.d index a6a4bd76..7e92d954 100644 --- a/source/mir/bignum/fixed.d +++ b/source/mir/bignum/fixed.d @@ -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; diff --git a/source/mir/bignum/integer.d b/source/mir/bignum/integer.d index 9ea01a2d..817d5814 100644 --- a/source/mir/bignum/integer.d +++ b/source/mir/bignum/integer.d @@ -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; @@ -317,6 +317,45 @@ 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: @@ -324,29 +363,67 @@ struct BigInt(size_t maxSize64) 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; } /++ @@ -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) @@ -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); } }