From 079b16c51e2434e39d45169c69a5ea19564ea446 Mon Sep 17 00:00:00 2001 From: Pagwin Date: Wed, 11 Dec 2024 20:15:22 -0500 Subject: [PATCH] more tests and bug fixes forgot to commit sooner integer.cpp --- integer.cpp | 128 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 100 insertions(+), 28 deletions(-) diff --git a/integer.cpp b/integer.cpp index d6db35d..c5ade04 100644 --- a/integer.cpp +++ b/integer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -23,9 +24,10 @@ public: Integer(long long num = 0) : bytes{new byte[sizeof(long long)]}, isNegative{num < 0}, size{sizeof(long long)} { + unsigned long long n = std::llabs(num); for (std::size_t i = 0; i < size; i++) { - bytes[i] = num % 256; - num /= 256; + bytes[i] = n % 256; + n /= 256; } } Integer(Integer const &rhs) @@ -102,15 +104,18 @@ public: friend Integer &abs_add(Integer &lhs, Integer const &rhs) { bool overflow = false; + bool prev_overflow; for (std::size_t i = 0; i < std::min(lhs.size, rhs.size); i++) { - if (std::numeric_limits::max() - lhs.bytes[i] <= rhs.bytes[i]) { + prev_overflow = overflow; + overflow = false; + if (std::numeric_limits::max() - lhs.bytes[i] < rhs.bytes[i]) { overflow = true; } else if (std::numeric_limits::max() - lhs.bytes[i] - - (rhs.bytes[i]) <= - (overflow ? 1 : 0)) { + (rhs.bytes[i]) < + (prev_overflow ? 1 : 0)) { overflow = true; } - lhs.bytes[i] += rhs.bytes[i] + (overflow ? 1 : 0); + lhs.bytes[i] += rhs.bytes[i] + (prev_overflow ? 1 : 0); } if (overflow) { std::size_t idx = std::min(lhs.size, rhs.size); @@ -129,19 +134,27 @@ public: return lhs; } friend Integer &abs_sub(Integer &lhs, Integer const &rhs) { - assert(lhs > rhs); - auto t_size = rhs.true_size(); + assert(abs_lt(rhs, lhs)); + auto r_size = rhs.true_size(); + auto t_size = r_size + (lhs.true_size() > r_size ? 1 : 0); bool overflow = false; for (std::size_t i = 0; i < t_size; i++) { - if (rhs.bytes[i] + (overflow ? 1 : 0) > lhs.bytes[i]) { - overflow = true; + byte to_sub = 0; + byte overflow_handle = (overflow ? 1 : 0); + overflow = false; + if (r_size > i) { + to_sub = rhs.bytes[i]; + if (to_sub + overflow_handle > lhs.bytes[i] || + // overflow detection + (to_sub + overflow_handle == 0 && to_sub != 0)) { + overflow = true; + } } - lhs.bytes[i] -= rhs.bytes[i] + (overflow ? 1 : 0); + lhs.bytes[i] -= to_sub + overflow_handle; } return lhs; } friend Integer &operator+=(Integer &lhs, Integer const &rhs) { - // TODO: negative numbers if (lhs.isNegative == rhs.isNegative) { return abs_add(lhs, rhs); } else { @@ -171,16 +184,19 @@ public: return lhs; } friend Integer &operator/=(Integer &lhs, Integer const &rhs) { + bool sign = lhs.isNegative != rhs.isNegative; + lhs.isNegative = rhs.isNegative; Integer tmp = std::move(lhs); lhs = 0; - while (tmp > rhs) { + while (tmp > rhs || tmp == rhs) { tmp -= rhs; lhs += 1; } + lhs.isNegative = sign; return lhs; } friend Integer &operator%=(Integer &lhs, Integer const &rhs) { - while (lhs > rhs) { + while (lhs >= rhs) { lhs -= rhs; } return lhs; @@ -210,19 +226,14 @@ public: ret %= rhs; return ret; } - friend Integer operator%(Integer const &lhs, byte rhs) { - if (lhs.size == 0 || lhs.bytes == nullptr) { - return 0; - } - return lhs.bytes[0] % rhs; - } friend Integer operator-(Integer const &val) { Integer ret = val; ret.isNegative = !ret.isNegative; return ret; } friend bool operator<(Integer const &lhs, Integer const &rhs) { - if (lhs.isNegative != rhs.isNegative) { + if (lhs.isNegative != rhs.isNegative && lhs != Integer{0} && + rhs != Integer{0}) { return lhs.isNegative; } else { return abs_lt(lhs, rhs); @@ -231,11 +242,26 @@ public: friend bool operator>(Integer const &lhs, Integer const &rhs) { return rhs < lhs; } + friend bool operator>=(Integer const &lhs, Integer const &rhs) { + return lhs > rhs || lhs == rhs; + } + friend bool operator<=(Integer const &lhs, Integer const &rhs) { + return rhs < lhs || rhs == lhs; + } friend bool operator==(Integer const &lhs, Integer const &rhs) { auto l_true = lhs.true_size(); - return l_true == rhs.true_size() && + auto r_true = rhs.true_size(); + if (l_true == 1 && r_true == 1) { + if (lhs.bytes[0] == rhs.bytes[0] && lhs.bytes[0] == 0) { + return true; + } + } + return l_true == rhs.true_size() && lhs.isNegative == rhs.isNegative && std::equal(lhs.bytes, lhs.bytes + l_true, rhs.bytes); } + friend bool operator!=(Integer const &lhs, Integer const &rhs) { + return !(lhs == rhs); + } friend std::ostream &operator<<(std::ostream &lhs, Integer const &rhs) { if (rhs == 0) { @@ -246,7 +272,8 @@ public: Integer discard = rhs; std::stringstream to_output{}; while (discard != Integer{0}) { - to_output << discard % static_cast(10); + int a = discard % Integer{10}; + to_output << a; discard /= 10; } std::string out; @@ -266,10 +293,55 @@ public: }; int main(void) { - for (std::size_t i = 0; i <= 8584148901; i++) { - unsigned long n = i * i; - n = i + i; - n = i - i; - n = i / i; + Integer a = std::numeric_limits::max(); + Integer b = a; + a += a; + assert(a / b == Integer{2}); + a = std::numeric_limits::min(); + b = a; + a += a; + assert(a / b == Integer{2}); + a = std::numeric_limits::max(); + b = a; + a = -a; + a += a; + assert(a / b == Integer{-2}); + a = std::numeric_limits::min(); + b = a; + a = -a; + a += a; + assert(a / b == Integer{-2}); + a = std::numeric_limits::max(); + b = a; + for (std::size_t i = 2; i < 20; i++) { + a += b; + assert(b * Integer{static_cast(i)} == a); + } + for (std::size_t i = 0; i <= 4500; i++) { + Integer n = i; + std::cout << n << std::endl; + Integer base_n = n; + n *= 1; + assert(n == base_n); + n += 0; + assert(n == base_n); + n /= 1; + assert(n == base_n); + n -= 0; + assert(n == base_n); + + assert(n - n == Integer{0}); + assert(-n + n == Integer{0}); + assert(-n + (n - Integer{1}) == Integer{-1}); + assert(n * Integer{0} == Integer{0}); + assert(Integer{-static_cast(i)} + n == Integer{0}); + if (n == Integer{0}) { + continue; + } + assert(n - Integer{1} == Integer{static_cast(i - 1)}); + assert(Integer{-1} + n == Integer{static_cast(i - 1)}); + assert((n + n) / n == Integer{2}); + assert((n * n) / n == n); + assert(n / n == Integer{1}); } }