260 lines
6.6 KiB
C++
260 lines
6.6 KiB
C++
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <sstream>
|
|
#include <string>
|
|
#define todo(msg) \
|
|
std::cerr << msg << std::endl; \
|
|
assert(false);
|
|
// TODO: try to maximize rvalue usage to reuse resources
|
|
// "Use rvalue references to reuse the resources of temporaries when possible,
|
|
// particularly for binary operands."
|
|
|
|
class Integer {
|
|
using byte = unsigned char;
|
|
// bytes are litle endian
|
|
byte *bytes;
|
|
bool isNegative;
|
|
std::size_t size;
|
|
|
|
public:
|
|
Integer(long long num = 0)
|
|
: bytes{new byte[sizeof(long long)]}, isNegative{num < 0},
|
|
size{sizeof(long long)} {
|
|
for (std::size_t i = 0; i < size; i++) {
|
|
bytes[i] = num % 256;
|
|
num /= 256;
|
|
}
|
|
}
|
|
Integer(Integer const &rhs)
|
|
: bytes{new byte[rhs.size]}, isNegative{rhs.isNegative}, size{rhs.size} {
|
|
for (std::size_t i = 0; i < size; i++) {
|
|
bytes[i] = rhs.bytes[i];
|
|
}
|
|
}
|
|
Integer(Integer &&rhs)
|
|
: bytes{rhs.bytes}, isNegative{rhs.isNegative}, size{rhs.size} {
|
|
rhs.bytes = nullptr;
|
|
}
|
|
~Integer() {
|
|
delete[] bytes;
|
|
bytes = nullptr;
|
|
}
|
|
Integer &operator=(Integer const &rhs) {
|
|
delete[] bytes;
|
|
|
|
bytes = new byte[rhs.size];
|
|
size = rhs.size;
|
|
isNegative = rhs.isNegative;
|
|
for (std::size_t i = 0; i < size; i++) {
|
|
bytes[i] = rhs.bytes[i];
|
|
}
|
|
return *this;
|
|
}
|
|
Integer &operator=(Integer &&rhs) {
|
|
bytes = rhs.bytes;
|
|
rhs.bytes = nullptr;
|
|
size = rhs.size;
|
|
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 (idx >= 0) {
|
|
if (lhs.bytes[idx] != rhs.bytes[idx]) {
|
|
return lhs.bytes[idx] < rhs.bytes[idx];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
friend Integer &abs_add(Integer &lhs, Integer const &rhs) {
|
|
bool overflow = false;
|
|
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]) {
|
|
overflow = true;
|
|
} else if (std::numeric_limits<byte>::max() - lhs.bytes[i] -
|
|
(rhs.bytes[i]) <=
|
|
(overflow ? 1 : 0)) {
|
|
overflow = true;
|
|
}
|
|
lhs.bytes[i] += rhs.bytes[i] + (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) { return lhs; }
|
|
friend Integer &operator+=(Integer &lhs, Integer const &rhs) {
|
|
// TODO: negative numbers
|
|
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;
|
|
return lhs;
|
|
}
|
|
}
|
|
}
|
|
friend Integer &operator-=(Integer &lhs, Integer const &rhs) {
|
|
return lhs += -rhs;
|
|
}
|
|
friend Integer &operator*=(Integer &lhs, Integer const &rhs) {
|
|
Integer tmp = std::move(lhs);
|
|
Integer tmp_r = rhs;
|
|
lhs = 0;
|
|
while (tmp_r > 0) {
|
|
lhs += tmp;
|
|
tmp_r -= 1;
|
|
}
|
|
return lhs;
|
|
}
|
|
friend Integer &operator/=(Integer &lhs, Integer const &rhs) {
|
|
Integer tmp = std::move(lhs);
|
|
lhs = 0;
|
|
while (tmp > rhs) {
|
|
tmp -= rhs;
|
|
lhs += 1;
|
|
}
|
|
return lhs;
|
|
}
|
|
friend Integer &operator%=(Integer &lhs, Integer const &rhs) {
|
|
while (lhs > rhs) {
|
|
lhs -= rhs;
|
|
}
|
|
return lhs;
|
|
}
|
|
friend Integer operator+(Integer const &lhs, Integer const &rhs) {
|
|
Integer ret{lhs};
|
|
ret += rhs;
|
|
return ret;
|
|
}
|
|
friend Integer operator-(Integer const &lhs, Integer const &rhs) {
|
|
Integer ret{lhs};
|
|
ret -= rhs;
|
|
return ret;
|
|
}
|
|
friend Integer operator*(Integer const &lhs, Integer const &rhs) {
|
|
Integer ret{lhs};
|
|
ret *= rhs;
|
|
return ret;
|
|
}
|
|
friend Integer operator/(Integer const &lhs, Integer const &rhs) {
|
|
Integer ret{lhs};
|
|
ret /= rhs;
|
|
return ret;
|
|
}
|
|
friend Integer operator%(Integer const &lhs, Integer const &rhs) {
|
|
Integer ret{lhs};
|
|
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) {
|
|
return lhs.isNegative;
|
|
} else {
|
|
return abs_lt(lhs, rhs);
|
|
}
|
|
}
|
|
friend bool operator>(Integer const &lhs, Integer const &rhs) {
|
|
return rhs < lhs;
|
|
}
|
|
friend bool operator==(Integer const &lhs, Integer const &rhs) {
|
|
auto l_true = lhs.true_size();
|
|
return l_true == rhs.true_size() &&
|
|
std::equal(lhs.bytes, lhs.bytes + l_true, rhs.bytes);
|
|
}
|
|
|
|
friend std::ostream &operator<<(std::ostream &lhs, Integer const &rhs) {
|
|
if (rhs == 0) {
|
|
lhs << 0;
|
|
return lhs;
|
|
}
|
|
|
|
Integer discard = rhs;
|
|
std::stringstream to_output{};
|
|
while (discard != 0) {
|
|
to_output << discard % 10;
|
|
discard /= 10;
|
|
}
|
|
std::string out;
|
|
to_output >> out;
|
|
std::reverse(out.begin(), out.end());
|
|
lhs << out;
|
|
return lhs;
|
|
}
|
|
|
|
explicit operator unsigned long() {
|
|
unsigned long ret = 0;
|
|
for (std::size_t i = 0; i < std::min(size, sizeof(unsigned long)); i++) {
|
|
ret += (static_cast<unsigned long>(this->bytes[i]) << (i * 8));
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
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;
|
|
}
|
|
}
|