more tests and bug fixes forgot to commit sooner integer.cpp

This commit is contained in:
Pagwin 2024-12-11 20:15:22 -05:00
parent b655135ea4
commit 079b16c51e
No known key found for this signature in database
GPG key ID: 81137023740CA260

View file

@ -1,6 +1,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <sstream> #include <sstream>
@ -23,9 +24,10 @@ public:
Integer(long long num = 0) Integer(long long num = 0)
: bytes{new byte[sizeof(long long)]}, isNegative{num < 0}, : bytes{new byte[sizeof(long long)]}, isNegative{num < 0},
size{sizeof(long long)} { size{sizeof(long long)} {
unsigned long long n = std::llabs(num);
for (std::size_t i = 0; i < size; i++) { for (std::size_t i = 0; i < size; i++) {
bytes[i] = num % 256; bytes[i] = n % 256;
num /= 256; n /= 256;
} }
} }
Integer(Integer const &rhs) Integer(Integer const &rhs)
@ -102,15 +104,18 @@ public:
friend Integer &abs_add(Integer &lhs, Integer const &rhs) { friend Integer &abs_add(Integer &lhs, Integer const &rhs) {
bool overflow = false; bool overflow = false;
bool prev_overflow;
for (std::size_t i = 0; i < std::min(lhs.size, rhs.size); i++) { for (std::size_t i = 0; i < std::min(lhs.size, rhs.size); i++) {
if (std::numeric_limits<byte>::max() - lhs.bytes[i] <= rhs.bytes[i]) { prev_overflow = overflow;
overflow = false;
if (std::numeric_limits<byte>::max() - lhs.bytes[i] < rhs.bytes[i]) {
overflow = true; overflow = true;
} else if (std::numeric_limits<byte>::max() - lhs.bytes[i] - } else if (std::numeric_limits<byte>::max() - lhs.bytes[i] -
(rhs.bytes[i]) <= (rhs.bytes[i]) <
(overflow ? 1 : 0)) { (prev_overflow ? 1 : 0)) {
overflow = true; overflow = true;
} }
lhs.bytes[i] += rhs.bytes[i] + (overflow ? 1 : 0); lhs.bytes[i] += rhs.bytes[i] + (prev_overflow ? 1 : 0);
} }
if (overflow) { if (overflow) {
std::size_t idx = std::min(lhs.size, rhs.size); std::size_t idx = std::min(lhs.size, rhs.size);
@ -129,19 +134,27 @@ public:
return lhs; return lhs;
} }
friend Integer &abs_sub(Integer &lhs, Integer const &rhs) { friend Integer &abs_sub(Integer &lhs, Integer const &rhs) {
assert(lhs > rhs); assert(abs_lt(rhs, lhs));
auto t_size = rhs.true_size(); auto r_size = rhs.true_size();
auto t_size = r_size + (lhs.true_size() > r_size ? 1 : 0);
bool overflow = false; bool overflow = false;
for (std::size_t i = 0; i < t_size; i++) { for (std::size_t i = 0; i < t_size; i++) {
if (rhs.bytes[i] + (overflow ? 1 : 0) > lhs.bytes[i]) { 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; overflow = true;
} }
lhs.bytes[i] -= rhs.bytes[i] + (overflow ? 1 : 0); }
lhs.bytes[i] -= to_sub + overflow_handle;
} }
return lhs; return lhs;
} }
friend Integer &operator+=(Integer &lhs, Integer const &rhs) { friend Integer &operator+=(Integer &lhs, Integer const &rhs) {
// TODO: negative numbers
if (lhs.isNegative == rhs.isNegative) { if (lhs.isNegative == rhs.isNegative) {
return abs_add(lhs, rhs); return abs_add(lhs, rhs);
} else { } else {
@ -171,16 +184,19 @@ public:
return lhs; return lhs;
} }
friend Integer &operator/=(Integer &lhs, Integer const &rhs) { friend Integer &operator/=(Integer &lhs, Integer const &rhs) {
bool sign = lhs.isNegative != rhs.isNegative;
lhs.isNegative = rhs.isNegative;
Integer tmp = std::move(lhs); Integer tmp = std::move(lhs);
lhs = 0; lhs = 0;
while (tmp > rhs) { while (tmp > rhs || tmp == rhs) {
tmp -= rhs; tmp -= rhs;
lhs += 1; lhs += 1;
} }
lhs.isNegative = sign;
return lhs; return lhs;
} }
friend Integer &operator%=(Integer &lhs, Integer const &rhs) { friend Integer &operator%=(Integer &lhs, Integer const &rhs) {
while (lhs > rhs) { while (lhs >= rhs) {
lhs -= rhs; lhs -= rhs;
} }
return lhs; return lhs;
@ -210,19 +226,14 @@ public:
ret %= rhs; ret %= rhs;
return ret; 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) { friend Integer operator-(Integer const &val) {
Integer ret = val; Integer ret = val;
ret.isNegative = !ret.isNegative; ret.isNegative = !ret.isNegative;
return ret; return ret;
} }
friend bool operator<(Integer const &lhs, Integer const &rhs) { 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; return lhs.isNegative;
} else { } else {
return abs_lt(lhs, rhs); return abs_lt(lhs, rhs);
@ -231,11 +242,26 @@ public:
friend bool operator>(Integer const &lhs, Integer const &rhs) { friend bool operator>(Integer const &lhs, Integer const &rhs) {
return rhs < lhs; 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) { friend bool operator==(Integer const &lhs, Integer const &rhs) {
auto l_true = lhs.true_size(); 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); 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) { friend std::ostream &operator<<(std::ostream &lhs, Integer const &rhs) {
if (rhs == 0) { if (rhs == 0) {
@ -246,7 +272,8 @@ public:
Integer discard = rhs; Integer discard = rhs;
std::stringstream to_output{}; std::stringstream to_output{};
while (discard != Integer{0}) { while (discard != Integer{0}) {
to_output << discard % static_cast<byte>(10); int a = discard % Integer{10};
to_output << a;
discard /= 10; discard /= 10;
} }
std::string out; std::string out;
@ -266,10 +293,55 @@ public:
}; };
int main(void) { int main(void) {
for (std::size_t i = 0; i <= 8584148901; i++) { Integer a = std::numeric_limits<long long>::max();
unsigned long n = i * i; Integer b = a;
n = i + i; a += a;
n = i - i; assert(a / b == Integer{2});
n = i / i; a = std::numeric_limits<long long>::min();
b = a;
a += a;
assert(a / b == Integer{2});
a = std::numeric_limits<long long>::max();
b = a;
a = -a;
a += a;
assert(a / b == Integer{-2});
a = std::numeric_limits<long long>::min();
b = a;
a = -a;
a += a;
assert(a / b == Integer{-2});
a = std::numeric_limits<long long>::max();
b = a;
for (std::size_t i = 2; i < 20; i++) {
a += b;
assert(b * Integer{static_cast<long long>(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<long long>(i)} + n == Integer{0});
if (n == Integer{0}) {
continue;
}
assert(n - Integer{1} == Integer{static_cast<long long>(i - 1)});
assert(Integer{-1} + n == Integer{static_cast<long long>(i - 1)});
assert((n + n) / n == Integer{2});
assert((n * n) / n == n);
assert(n / n == Integer{1});
} }
} }