cs440-final/integer.cpp

243 lines
6.1 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 &operator+=(Integer &lhs, Integer const &rhs) {
// TODO: negative numbers
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 &operator-=(Integer &lhs, Integer const &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 > 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;
}
}