feat(big): add Div

This commit is contained in:
fallenoak 2023-02-03 16:57:14 -06:00
parent 25c2ad06f1
commit 8845aa5a7f
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
3 changed files with 198 additions and 0 deletions

View file

@ -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<uint32_t>(value);
value >>= 32;

View file

@ -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);

View file

@ -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<uint8_t*>(&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<uint8_t*>(&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]") {