Compare commits
No commits in common. "4f344d825bd631abcb63807c2e3f214568ea9e68" and "01c0cbb0ec9d01e21fd4c0ae9833c501c761b3a3" have entirely different histories.
4f344d825b
...
01c0cbb0ec
1 changed files with 29 additions and 200 deletions
227
integer.cpp
227
integer.cpp
|
@ -1,9 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#define todo(msg) \
|
||||
|
@ -24,10 +22,9 @@ 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] = n % 256;
|
||||
n /= 256;
|
||||
bytes[i] = num % 256;
|
||||
num /= 256;
|
||||
}
|
||||
}
|
||||
Integer(Integer const &rhs)
|
||||
|
@ -62,141 +59,35 @@ public:
|
|||
isNegative = rhs.isNegative;
|
||||
return *this;
|
||||
}
|
||||
void expand() {
|
||||
byte *new_buf = new byte[size + 1];
|
||||
std::copy(bytes, bytes + size, new_buf);
|
||||
size++;
|
||||
delete[] bytes;
|
||||
bytes = new_buf;
|
||||
}
|
||||
std::size_t true_size() const {
|
||||
std::size_t ret = size;
|
||||
if (bytes == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
while (bytes[ret - 1] == 0 && ret > 1) {
|
||||
ret--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
friend bool abs_lt(Integer const &lhs, Integer const &rhs) {
|
||||
std::size_t true_lhs_size = lhs.true_size();
|
||||
std::size_t true_rhs_size = rhs.true_size();
|
||||
if (true_lhs_size != true_rhs_size) {
|
||||
return true_lhs_size < true_rhs_size;
|
||||
}
|
||||
if (true_lhs_size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto idx = true_lhs_size - 1;
|
||||
while (true) {
|
||||
if (lhs.bytes[idx] != rhs.bytes[idx]) {
|
||||
return lhs.bytes[idx] < rhs.bytes[idx];
|
||||
}
|
||||
if (idx == 0) {
|
||||
break;
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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++) {
|
||||
prev_overflow = overflow;
|
||||
overflow = false;
|
||||
if (std::numeric_limits<byte>::max() - lhs.bytes[i] < rhs.bytes[i]) {
|
||||
overflow = true;
|
||||
} else if (std::numeric_limits<byte>::max() - lhs.bytes[i] -
|
||||
(rhs.bytes[i]) <
|
||||
(prev_overflow ? 1 : 0)) {
|
||||
overflow = true;
|
||||
}
|
||||
lhs.bytes[i] += rhs.bytes[i] + (prev_overflow ? 1 : 0);
|
||||
}
|
||||
if (overflow) {
|
||||
std::size_t idx = std::min(lhs.size, rhs.size);
|
||||
if (idx == lhs.size) {
|
||||
lhs.expand();
|
||||
}
|
||||
lhs.bytes[idx]++;
|
||||
if (lhs.bytes[idx] == 0) {
|
||||
idx++;
|
||||
if (idx == lhs.size) {
|
||||
lhs.expand();
|
||||
}
|
||||
lhs.bytes[idx]++;
|
||||
}
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
friend Integer &abs_sub(Integer &lhs, Integer const &rhs) {
|
||||
assert(abs_lt(rhs, lhs));
|
||||
auto r_size = rhs.true_size();
|
||||
auto t_size = lhs.true_size();
|
||||
bool overflow = false;
|
||||
for (std::size_t i = 0; i < t_size; 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;
|
||||
}
|
||||
lhs.bytes[i] -= to_sub + overflow_handle;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
friend Integer &operator+=(Integer &lhs, Integer const &rhs) {
|
||||
if (lhs.isNegative == rhs.isNegative) {
|
||||
return abs_add(lhs, rhs);
|
||||
} else {
|
||||
if (abs_lt(rhs, lhs)) {
|
||||
return abs_sub(lhs, rhs);
|
||||
} else if (abs_lt(lhs, rhs)) {
|
||||
Integer tmp = std::move(lhs);
|
||||
lhs = rhs;
|
||||
return abs_sub(lhs, tmp);
|
||||
} else {
|
||||
lhs = 0;
|
||||
todo("+=");
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
friend Integer &operator-=(Integer &lhs, Integer const &rhs) {
|
||||
return lhs += -rhs;
|
||||
todo("-=");
|
||||
return lhs;
|
||||
}
|
||||
friend Integer &operator*=(Integer &lhs, Integer const &rhs) {
|
||||
Integer tmp = std::move(lhs);
|
||||
Integer tmp_r = rhs;
|
||||
lhs = 0;
|
||||
while (tmp_r > Integer{0}) {
|
||||
while (tmp_r > 0) {
|
||||
lhs += tmp;
|
||||
tmp_r -= 1;
|
||||
}
|
||||
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 || tmp == rhs) {
|
||||
while (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;
|
||||
|
@ -226,41 +117,29 @@ 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 && lhs != Integer{0} &&
|
||||
rhs != Integer{0}) {
|
||||
return lhs.isNegative;
|
||||
} else {
|
||||
return abs_lt(lhs, rhs);
|
||||
}
|
||||
Integer tmp = (lhs - rhs);
|
||||
return tmp.isNegative && tmp != 0;
|
||||
}
|
||||
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;
|
||||
Integer tmp = (rhs - lhs);
|
||||
return tmp.isNegative && tmp != 0;
|
||||
}
|
||||
friend bool operator==(Integer const &lhs, Integer const &rhs) {
|
||||
auto l_true = lhs.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);
|
||||
todo("need to actually do a check for the case that one or both of them is "
|
||||
"0");
|
||||
return (rhs - lhs) == 0;
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &lhs, Integer const &rhs) {
|
||||
|
@ -271,9 +150,8 @@ public:
|
|||
|
||||
Integer discard = rhs;
|
||||
std::stringstream to_output{};
|
||||
while (discard != Integer{0}) {
|
||||
int a = static_cast<unsigned long>(discard % Integer{10});
|
||||
to_output << a;
|
||||
while (discard != 0) {
|
||||
to_output << discard % 10;
|
||||
discard /= 10;
|
||||
}
|
||||
std::string out;
|
||||
|
@ -293,59 +171,10 @@ public:
|
|||
};
|
||||
|
||||
int main(void) {
|
||||
Integer a = std::numeric_limits<long long>::max();
|
||||
Integer b = a;
|
||||
a += a;
|
||||
assert(a / b == Integer{2});
|
||||
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 (unsigned long i = 0; i < 20; i++) {
|
||||
Integer n = i;
|
||||
assert(((unsigned long)n ^ i) == 0);
|
||||
}
|
||||
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 <= 10000; 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});
|
||||
for (std::size_t i = 0; i <= 8584148901; i++) {
|
||||
unsigned long n = i * i;
|
||||
n = i + i;
|
||||
n = i - i;
|
||||
n = i / i;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue