From 8845aa5a7f76fefbe6b903cea2639804d0b91355 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Fri, 3 Feb 2023 16:57:14 -0600 Subject: [PATCH] feat(big): add Div --- storm/big/Ops.cpp | 70 ++++++++++++++++++++++++++ storm/big/Ops.hpp | 2 + test/Big.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) diff --git a/storm/big/Ops.cpp b/storm/big/Ops.cpp index 75ff524..a2ff20a 100644 --- a/storm/big/Ops.cpp +++ b/storm/big/Ops.cpp @@ -51,6 +51,76 @@ void Div(BigBuffer& a, uint32_t* b, const BigBuffer& c, uint64_t d) { *b = data; } +void Div(BigBuffer& a, BigBuffer& b, const BigBuffer& c, const BigBuffer& d, BigStack& stack) { + c.Trim(); + d.Trim(); + + auto cCount = c.Count(); + auto dCount = d.Count(); + + if (dCount > cCount) { + SetZero(b = c); + + return; + } + + if (dCount <= 1) { + Div(a, &b[0], c, d[0]); + b.SetCount(1); + + return; + } + + uint32_t allocCount = 0; + auto& cc = stack.Alloc(&allocCount); + auto& dd = stack.Alloc(&allocCount); + auto& work = stack.Alloc(&allocCount); + + uint32_t shift = 0x1F - (HighBitPos(work) & 0x1F); + Shl(cc, c, shift); + Shl(dd, d, shift); + + uint32_t t = dd[dCount - 1] + 1; + auto v12 = cCount - dCount + 1; + a.SetCount(v12); + + uint32_t index; + if (v12) { + while (true) { + index = v12 - 1; + a.SetOffset(v12 - 1); + cc.SetOffset(v12 - 1); + + if (t) { + a[0] = MakeLarge(cc[dCount - 1], cc[dCount]) / t; + } else { + a[0] = cc[dCount]; + } + + if (a[0]) { + Mul(work, dd, a[0]); + Sub(cc, cc, work); + } + + while (cc[dCount] || Compare(cc, dd) >= 0) { + a[0]++; + Sub(cc, cc, dd); + } + + if (index == 0) { + break; + } + + v12 = index; + } + } + + Shr(b, cc, shift); + b.Trim(); + + stack.Free(allocCount); +} + uint32_t ExtractLowPart(uint64_t& value) { auto low = static_cast(value); value >>= 32; diff --git a/storm/big/Ops.hpp b/storm/big/Ops.hpp index 600f3e4..d4f22e3 100644 --- a/storm/big/Ops.hpp +++ b/storm/big/Ops.hpp @@ -13,6 +13,8 @@ int32_t Compare(const BigBuffer& a, const BigBuffer& b); void Div(BigBuffer& a, uint32_t* b, const BigBuffer& c, uint64_t d); +void Div(BigBuffer& a, BigBuffer& b, const BigBuffer& c, const BigBuffer& d, BigStack& stack); + uint32_t ExtractLowPart(uint64_t& value); uint32_t ExtractLowPartLargeSum(uint64_t& value, uint64_t add); diff --git a/test/Big.cpp b/test/Big.cpp index 24798ed..539622f 100644 --- a/test/Big.cpp +++ b/test/Big.cpp @@ -170,6 +170,36 @@ TEST_CASE("Div", "[big]") { SBigDel(c); } + SECTION("divides 2 by 1 (buffer divisor)") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 2); + + BigData* d; + SBigNew(&d); + SBigFromUnsigned(d, 1); + + Div(a->Primary(), b->Primary(), c->Primary(), d->Primary(), a->Stack()); + + a->Primary().Trim(); + b->Primary().Trim(); + + CHECK(a->Primary().Count() == 1); + CHECK(a->Primary()[0] == 2); + CHECK(b->Primary().Count() == 0); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + SBigDel(d); + } + SECTION("divides 5 by 2") { BigData* a; SBigNew(&a); @@ -214,6 +244,37 @@ TEST_CASE("Div", "[big]") { SBigDel(c); } + SECTION("divides 7 by 4 (buffer divisor)") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 7); + + BigData* d; + SBigNew(&d); + SBigFromUnsigned(d, 4); + + Div(a->Primary(), b->Primary(), c->Primary(), d->Primary(), a->Stack()); + + a->Primary().Trim(); + b->Primary().Trim(); + + CHECK(a->Primary().Count() == 1); + CHECK(a->Primary()[0] == 1); + CHECK(b->Primary().Count() == 1); + CHECK(b->Primary()[0] == 3); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + SBigDel(d); + } + SECTION("divides 0x9999444488885555 by 0x2222") { BigData* a; SBigNew(&a); @@ -238,6 +299,39 @@ TEST_CASE("Div", "[big]") { SBigDel(c); } + SECTION("divides 0x9999444488885555 by 0x2222 (buffer divisor)") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + + BigData* c; + SBigNew(&c); + uint64_t c_ = 0x9999444488885555; + SBigFromBinary(c, reinterpret_cast(&c_), sizeof(c_)); + + BigData* d; + SBigNew(&d); + SBigFromUnsigned(d, 0x2222); + + Div(a->Primary(), b->Primary(), c->Primary(), d->Primary(), a->Stack()); + + a->Primary().Trim(); + b->Primary().Trim(); + + CHECK(a->Primary().Count() == 2); + CHECK(a->Primary()[0] == 0x00040002); + CHECK(a->Primary()[1] == 0x48002); + CHECK(b->Primary().Count() == 1); + CHECK(b->Primary()[0] == 0x1111); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + SBigDel(d); + } + SECTION("divides 0x9999444488885555 by 0xFFFFFFFF") { BigData* a; SBigNew(&a); @@ -260,6 +354,38 @@ TEST_CASE("Div", "[big]") { SBigDel(a); SBigDel(c); } + + SECTION("divides 0x9999444488885555 by 0xFFFFFFFF (buffer divisor)") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + + BigData* c; + SBigNew(&c); + uint64_t c_ = 0x9999444488885555; + SBigFromBinary(c, reinterpret_cast(&c_), sizeof(c_)); + + BigData* d; + SBigNew(&d); + SBigFromUnsigned(d, 0xFFFFFFFF); + + Div(a->Primary(), b->Primary(), c->Primary(), d->Primary(), a->Stack()); + + a->Primary().Trim(); + b->Primary().Trim(); + + CHECK(a->Primary().Count() == 1); + CHECK(a->Primary()[0] == 0x99994445); + CHECK(b->Primary().Count() == 1); + CHECK(b->Primary()[0] == 0x2221999A); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + SBigDel(d); + } } TEST_CASE("ExtractLowPart", "[big]") {