abacus: bignum: add addition & substraction
This commit is contained in:
parent
d083ede78c
commit
fe01661613
3 changed files with 203 additions and 0 deletions
|
|
@ -18,6 +18,57 @@ bool do_less_than(digits_type const& lhs, digits_type const& rhs) {
|
||||||
rhs.rend());
|
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
|
} // namespace
|
||||||
|
|
||||||
BigNum::BigNum(std::int64_t number) {
|
BigNum::BigNum(std::int64_t number) {
|
||||||
|
|
@ -60,6 +111,48 @@ void BigNum::flip_sign() {
|
||||||
sign_ *= -1;
|
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 {
|
bool BigNum::equal(BigNum const& rhs) const {
|
||||||
assert(is_canonicalized());
|
assert(is_canonicalized());
|
||||||
assert(rhs.is_canonicalized());
|
assert(rhs.is_canonicalized());
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,28 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend BigNum& operator+=(BigNum& lhs, BigNum const& rhs) {
|
||||||
|
lhs.add(rhs);
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend BigNum operator+(BigNum const& lhs, BigNum const& rhs) {
|
||||||
|
auto ret = lhs;
|
||||||
|
ret += rhs;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend BigNum& operator-=(BigNum& lhs, BigNum const& rhs) {
|
||||||
|
lhs.substract(rhs);
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend BigNum operator-(BigNum const& lhs, BigNum const& rhs) {
|
||||||
|
auto ret = lhs;
|
||||||
|
ret -= rhs;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
friend bool operator==(BigNum const& lhs, BigNum const& rhs) {
|
friend bool operator==(BigNum const& lhs, BigNum const& rhs) {
|
||||||
return lhs.equal(rhs);
|
return lhs.equal(rhs);
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +75,8 @@ private:
|
||||||
std::ostream& dump(std::ostream& out) const;
|
std::ostream& dump(std::ostream& out) const;
|
||||||
|
|
||||||
void flip_sign();
|
void flip_sign();
|
||||||
|
void add(BigNum const& rhs);
|
||||||
|
void substract(BigNum const& rhs);
|
||||||
|
|
||||||
bool equal(BigNum const& rhs) const;
|
bool equal(BigNum const& rhs) const;
|
||||||
bool less_than(BigNum const& rhs) const;
|
bool less_than(BigNum const& rhs) const;
|
||||||
|
|
|
||||||
|
|
@ -56,3 +56,89 @@ TEST(BigNum, unary) {
|
||||||
auto const minus_one = BigNum(-1);
|
auto const minus_one = BigNum(-1);
|
||||||
EXPECT_EQ(minus_one, -one);
|
EXPECT_EQ(minus_one, -one);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, addition_positive) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
|
||||||
|
EXPECT_EQ(zero + zero, zero);
|
||||||
|
EXPECT_EQ(zero + one, one);
|
||||||
|
EXPECT_EQ(one + zero, one);
|
||||||
|
EXPECT_EQ(one + one, two);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, addition_negative) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
auto const minus_two = BigNum(-2);
|
||||||
|
|
||||||
|
EXPECT_EQ(zero + zero, zero);
|
||||||
|
EXPECT_EQ(zero + minus_one, minus_one);
|
||||||
|
EXPECT_EQ(minus_one + zero, minus_one);
|
||||||
|
EXPECT_EQ(minus_one + minus_one, minus_two);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, addition_mixed_signs) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
|
||||||
|
EXPECT_EQ(one + minus_one, zero);
|
||||||
|
EXPECT_EQ(minus_one + one, zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, addition_flips_sign) {
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
auto const minus_two = BigNum(-2);
|
||||||
|
|
||||||
|
EXPECT_EQ(one + minus_two, minus_one);
|
||||||
|
EXPECT_EQ(minus_two + one, minus_one);
|
||||||
|
|
||||||
|
EXPECT_EQ(minus_one + two, one);
|
||||||
|
EXPECT_EQ(two + minus_one, one);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, substraction_positive) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
|
||||||
|
EXPECT_EQ(zero - zero, zero);
|
||||||
|
EXPECT_EQ(two - zero, two);
|
||||||
|
EXPECT_EQ(two - one, one);
|
||||||
|
EXPECT_EQ(one - one, zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, substraction_negative) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
|
||||||
|
EXPECT_EQ(zero - zero, zero);
|
||||||
|
EXPECT_EQ(zero - minus_one, one);
|
||||||
|
EXPECT_EQ(zero - one, minus_one);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, substraction_mixed_signs) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
auto const minus_two = BigNum(-2);
|
||||||
|
|
||||||
|
EXPECT_EQ(one - minus_one, two);
|
||||||
|
EXPECT_EQ(minus_one - one, minus_two);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, substraction_flips_sign) {
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
auto const minus_one = BigNum(-1);
|
||||||
|
auto const minus_two = BigNum(-2);
|
||||||
|
|
||||||
|
EXPECT_EQ(one - two, minus_one);
|
||||||
|
EXPECT_EQ(minus_one - minus_two, one);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue