abacus: bignum: add addition & substraction

This commit is contained in:
Bruno BELANYI 2021-08-20 18:53:22 +02:00
parent d083ede78c
commit fe01661613
3 changed files with 203 additions and 0 deletions

View file

@ -18,6 +18,57 @@ bool do_less_than(digits_type const& lhs, digits_type const& rhs) {
rhs.rend());
}
digits_type do_addition(digits_type const& lhs, digits_type const& rhs) {
int carry = 0;
digits_type res;
auto it1 = lhs.begin();
auto it2 = rhs.begin();
auto const end1 = lhs.end();
auto const end2 = rhs.end();
while (it1 != end1 && it2 != end2) {
int addition = *it1 + *it2 + carry;
carry = addition / 10;
res.push_back(addition % 10);
++it1;
++it2;
}
auto it = it1;
auto end = end1;
if (it1 == end1) {
it = it2;
end = end2;
}
while (it != end) {
int addition = *it + carry;
carry = addition / 10;
res.push_back(addition % 10);
++it;
}
return res;
}
digits_type do_substraction(digits_type const& lhs, digits_type const& rhs) {
assert(!do_less_than(lhs, rhs));
digits_type complement;
auto const take_complement = [](auto num) { return 9 - num; };
std::transform(lhs.begin(), lhs.end(), std::back_inserter(complement),
take_complement);
complement = do_addition(complement, rhs);
std::transform(complement.begin(), complement.end(), complement.begin(),
take_complement);
return complement;
}
} // namespace
BigNum::BigNum(std::int64_t number) {
@ -60,6 +111,48 @@ void BigNum::flip_sign() {
sign_ *= -1;
}
void BigNum::add(BigNum const& rhs) {
assert(is_canonicalized());
assert(rhs.is_canonicalized());
if (rhs.sign_ == 0) {
return;
}
if (sign_ == 0) {
*this = rhs;
return;
}
if (sign_ == rhs.sign_) {
digits_ = do_addition(digits_, rhs.digits_);
} else {
bool flipped = do_less_than(digits_, rhs.digits_);
if (flipped) {
digits_ = do_substraction(rhs.digits_, digits_);
} else {
digits_ = do_substraction(digits_, rhs.digits_);
}
if (flipped) {
flip_sign();
}
canonicalize();
}
assert(is_canonicalized());
}
void BigNum::substract(BigNum const& rhs) {
assert(is_canonicalized());
assert(rhs.is_canonicalized());
flip_sign();
add(rhs);
flip_sign();
assert(is_canonicalized());
}
bool BigNum::equal(BigNum const& rhs) const {
assert(is_canonicalized());
assert(rhs.is_canonicalized());