Skip to content

Commit

Permalink
Properly implement division and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Herts committed May 21, 2024
1 parent 898a2d1 commit 4b31f30
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 141 deletions.
217 changes: 77 additions & 140 deletions bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ namespace bigint_ns {
// return sum % 3;
// }

// auto div = lhs / rhs;
// auto mult = div * rhs;
// auto sub = lhs - mult;
//
// return sub;

return lhs - ((lhs / rhs) * rhs);
}

Expand All @@ -93,6 +99,25 @@ namespace bigint_ns {
{
return input.str.insert(0, "-");
}
inline static bool less_than(const bigint& lhs, const bigint& rhs)
{
if (is_negative(lhs) && is_negative(rhs))
{
return less_than(abs(rhs), abs(lhs));
}

if (is_negative(lhs) || is_negative(rhs))
{
return is_negative(lhs);
}

if(lhs.str.length() == rhs.str.length())
{
return lhs.str < rhs.str;
}

return lhs.str.length() < rhs.str.length();
}

public:
bool is_big = false;
Expand Down Expand Up @@ -234,37 +259,22 @@ namespace bigint_ns {

bigint operator*=(const bigint &rhs)
{
if (!this->is_big) {
if (!rhs.is_big) {
if ((this->base_repr == -1 && rhs.base_repr == std::numeric_limits<long long>::min()) ||
(rhs.base_repr == -1 && this->base_repr == std::numeric_limits<long long>::min()) ||
(rhs.base_repr != 0 &&
this->base_repr > std::numeric_limits<long long>::max() / rhs.base_repr) ||
(rhs.base_repr != 0 &&
this->base_repr < std::numeric_limits<long long>::min() / rhs.base_repr))
{
*this = multiply(std::to_string(this->base_repr), std::to_string(rhs.base_repr));
}
else
{
this->base_repr *= rhs.base_repr;
}
}
else
{
*this = multiply(std::to_string(this->base_repr), rhs.str);
}
if (this->is_big || rhs.is_big)
{
*this = multiply(this->is_big ? this->str : std::to_string(this->base_repr), rhs.is_big ? rhs.str : std::to_string(rhs.base_repr));
}
else if ((this->base_repr == -1 && rhs.base_repr == std::numeric_limits<long long>::min()) ||
(rhs.base_repr == -1 && this->base_repr == std::numeric_limits<long long>::min()) ||
(rhs.base_repr != 0 &&
this->base_repr > std::numeric_limits<long long>::max() / rhs.base_repr) ||
(rhs.base_repr != 0 &&
this->base_repr < std::numeric_limits<long long>::min() / rhs.base_repr))
{
*this = multiply(std::to_string(this->base_repr), std::to_string(rhs.base_repr));
}
else
{
if (!rhs.is_big)
{
*this = multiply(this->str, std::to_string(rhs.base_repr));
}
else
{
*this = multiply(this->str, rhs.str);
}
this->base_repr *= rhs.base_repr;
}
return *this;
}
Expand All @@ -278,21 +288,15 @@ namespace bigint_ns {

bigint &operator/=(const bigint &rhs)
{
if (!this->is_big) {
if (!rhs.is_big) {
this->base_repr /= rhs.base_repr;
} else {
*this = divide(std::to_string(this->base_repr), rhs.str);
}
} else {
if (!rhs.is_big)
{
*this = divide( this->str, std::to_string(rhs.base_repr));
}
else{
*this = divide(this->str, rhs.str);
}
if (this->is_big || rhs.is_big)
{
*this = divide(this->is_big ? this->str : std::to_string(this->base_repr), rhs.is_big ? rhs.str : std::to_string(rhs.base_repr));
}
else
{
this->base_repr /= rhs.base_repr;
}

return *this;
}

Expand All @@ -305,19 +309,13 @@ namespace bigint_ns {

bigint operator%=(const bigint &rhs)
{
if (!this->is_big) {
if (!rhs.is_big) {
this->base_repr %= rhs.base_repr;
} else {
*this = mod(std::to_string(this->base_repr), rhs.str);
}
} else {
if (!rhs.is_big) {
*this = mod(this->str, std::to_string(rhs.base_repr));
}
else {
*this = mod(this->str, rhs.str);
}
if (this->is_big || rhs.is_big)
{
*this = mod(this->is_big ? this->str : std::to_string(this->base_repr), rhs.is_big ? rhs.str : std::to_string(rhs.base_repr));
}
else
{
this->base_repr %= rhs.base_repr;
}

return *this;
Expand Down Expand Up @@ -374,38 +372,15 @@ namespace bigint_ns {
// strict weak ordering.
friend bool operator<(const bigint &lhs, const bigint &rhs)
{
if (!lhs.is_big) {
if (!rhs.is_big) {
return lhs.base_repr < rhs.base_repr;
}
// TODO: Implement half
auto temp = std::to_string(lhs.base_repr);
if(temp.length() == rhs.str.length())
{
return temp < rhs.str;
}

return temp.length() < rhs.str.length();
}

if (is_negative(lhs) && is_negative(rhs)) {
return abs(lhs) > abs(rhs);
if (lhs.is_big || rhs.is_big)
{
return less_than(lhs.is_big ? lhs.str : std::to_string(lhs.base_repr), rhs.is_big ? rhs.str : std::to_string(rhs.base_repr));
}

if (is_negative(lhs)) {
return true;
}
return lhs.base_repr < rhs.base_repr;

if (is_negative(rhs)) {
return false;
}

if(lhs.str.length() == rhs.str.length())
{
return lhs.str < rhs.str;
}

return lhs.str.length() < rhs.str.length();
}

friend bool operator>(const bigint &l, const bigint &r)
Expand Down Expand Up @@ -727,67 +702,29 @@ namespace bigint_ns {
return 0;
}

// As result can be very large store it in string
std::string ans;

// Find prefix of number that is larger
// than divisor.
int idx = 0;
bigint temp = char_to_int(numerator.str[idx]);
while (idx < (numerator.str.size() - 1) && temp < denominator) {
temp = temp * 10 + (char_to_int(numerator.str[++idx]));
}
// Repeatedly divide divisor with temp. After
// every division, update temp to include one
// more digit.
while ((numerator.str.size() - 1) > idx)
bigint count = "0";
bigint temp = numerator;
while(temp >= denominator)
{
// Store result in answer i.e. temp / divisor
ans += int_to_char(int(temp / int(denominator)));

// Take next digit of number
temp = char_to_int(int((temp % denominator) * 10 + numerator.str[++idx]));
}

ans += int_to_char(int(temp / int(denominator)));

// If divisor is greater than number
if (ans.length() == 0)
return "0";

// else return ans
return ans;


// TODO: Implement shortDivide
// if(str2.length() <= 19) {
// std::stringstream strstrm(str2);
// unsigned long long int int_str2 = 0;
// strstrm >> int_str2;
// ans = shortDivide(str1, int_str2);
// }
}

inline std::string bigint::shortDivide(std::string s1, unsigned long long int divisor)
{ // return arithmetic division of str1/str2
std::string ans;
int idx = 0;
long long int temp = s1[idx] - '0';

while (temp < divisor) {
temp = temp * 10 + (s1[++idx] - '0');
if (idx >= s1.length())
break;
}
while (s1.length() > idx) {
ans += (temp / divisor) + '0';
temp = (temp % divisor) * 10 + s1[++idx] - '0';
int lenDiff = temp.str.length() - denominator.str.length();
if(lenDiff > 0 && temp.str[0] > denominator.str[0])
{
count += pow(10, lenDiff);
temp -= denominator * pow(10, lenDiff);
}
else if(lenDiff > 0)
{
count += pow(10, lenDiff-1);
temp -= denominator * pow(10, lenDiff-1);
}
else
{
count++;
temp -= denominator;
}
}

if (ans.length() == 0)
return "0";

return ans;
return count;
}


Expand Down
5 changes: 4 additions & 1 deletion tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ TEST(BigInt_test, Multiplication_Tests)
bigint small_number = 9955;
bigint huge_number_1 = "123456789";
bigint huge_number_2 = "9999999999999999999";
bigint max_ll = LLONG_MAX;
ASSERT_EQ(bigint("30") * bigint("20"), "600");
ASSERT_EQ(small_number * 5, 49775);
ASSERT_EQ(small_number * small_number, 99102025);
ASSERT_EQ(small_number * max_ll, "91818668626889293158685");
ASSERT_EQ(huge_number_1 * 2, "246913578");
ASSERT_EQ(huge_number_2 * huge_number_2, "99999999999999999980000000000000000001");
}
Expand All @@ -82,10 +84,11 @@ TEST(BigInt_test, Division_Tests)
bigint small_number = 9955;
bigint huge_number_1 = "123456789";
bigint huge_number_2 = "9999999999999999999";
ASSERT_EQ(bigint("30") / bigint("20"), "1");
ASSERT_EQ(bigint("30") / bigint("20"), 1);
ASSERT_EQ(small_number / 5, 1991);
ASSERT_EQ(small_number / 181, 55);
ASSERT_EQ(huge_number_1 / 2, 61728394);
ASSERT_EQ(huge_number_1 / 3, 41152263);
ASSERT_EQ(huge_number_2 / huge_number_1, 81000000737);
}

Expand Down

0 comments on commit 4b31f30

Please sign in to comment.