|
|
@@ -18,8 +18,8 @@ namespace detail {
|
|
|
using data_type = biginteger::data_type;
|
|
|
// 1 => GREATER, 0 => EQUAL, -1 => LESS
|
|
|
int compare(data_type const & rhs, data_type const & lhs);
|
|
|
- data_type add(data_type rhs, data_type const & lhs);
|
|
|
- data_type subtract_nounderflow(data_type rhs, data_type const & lhs);
|
|
|
+ void add(data_type & rhs, data_type const & lhs);
|
|
|
+ void subtract_nounderflow(data_type & rhs, data_type const & lhs);
|
|
|
data_type multiply(data_type const & rhs, data_type const & lhs);
|
|
|
std::pair<data_type, data_type> divide(data_type remainder, data_type const & divisor);
|
|
|
}
|
|
|
@@ -78,22 +78,52 @@ is_negative(neg) {
|
|
|
biginteger::biginteger(bool neg, data_type && dt) :
|
|
|
is_negative(neg), data(std::move(dt)) {}
|
|
|
|
|
|
-biginteger & operator+=(biginteger & rhs, biginteger const & lhs) {
|
|
|
- swap(rhs, rhs + lhs);
|
|
|
+biginteger & math::operator+=(biginteger & rhs, biginteger const & lhs) {
|
|
|
+ if (lhs == biginteger::ZERO) { return rhs; }
|
|
|
+ else if (rhs == biginteger::ZERO) { rhs=lhs; }
|
|
|
+ else if (rhs.is_negative == lhs.is_negative) {
|
|
|
+ detail::add(rhs.data, lhs.data);
|
|
|
+ } else {
|
|
|
+ auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
+ if (cmp == 0) {
|
|
|
+ rhs = biginteger::ZERO;
|
|
|
+ } else if (cmp > 0) {
|
|
|
+ detail::subtract_nounderflow(rhs.data, lhs.data);
|
|
|
+ } else {
|
|
|
+ biginteger tmp{lhs};
|
|
|
+ swap(rhs, tmp);
|
|
|
+ detail::subtract_nounderflow(rhs.data, tmp.data);
|
|
|
+ }
|
|
|
+ }
|
|
|
return rhs;
|
|
|
}
|
|
|
|
|
|
-biginteger & operator-=(biginteger & rhs, biginteger const & lhs) {
|
|
|
- swap(rhs, rhs - lhs);
|
|
|
+biginteger & math::operator-=(biginteger & rhs, biginteger const & lhs) {
|
|
|
+ if (lhs == biginteger::ZERO) { return rhs; }
|
|
|
+ else if (rhs == biginteger::ZERO) { rhs = -lhs; }
|
|
|
+ if (rhs.is_negative != lhs.is_negative) {
|
|
|
+ detail::add(rhs.data, lhs.data);
|
|
|
+ } else {
|
|
|
+ auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
+ if (cmp == 0) {
|
|
|
+ rhs = biginteger::ZERO;
|
|
|
+ } else if (cmp > 0) {
|
|
|
+ detail::subtract_nounderflow(rhs.data, lhs.data);
|
|
|
+ } else {
|
|
|
+ biginteger tmp{-lhs};
|
|
|
+ swap(rhs, tmp);
|
|
|
+ detail::subtract_nounderflow(rhs.data, tmp.data);;
|
|
|
+ }
|
|
|
+ }
|
|
|
return rhs;
|
|
|
}
|
|
|
|
|
|
-biginteger & operator*=(biginteger & rhs, biginteger const & lhs) {
|
|
|
+biginteger & math::operator*=(biginteger & rhs, biginteger const & lhs) {
|
|
|
swap(rhs, rhs * lhs);
|
|
|
return rhs;
|
|
|
}
|
|
|
|
|
|
-biginteger & operator/=(biginteger & rhs, biginteger const & lhs) {
|
|
|
+biginteger & math::operator/=(biginteger & rhs, biginteger const & lhs) {
|
|
|
swap(rhs, rhs / lhs);
|
|
|
return rhs;
|
|
|
}
|
|
|
@@ -102,38 +132,12 @@ biginteger biginteger::operator-() const {
|
|
|
return (*this) * NEGATIVE_ONE;
|
|
|
}
|
|
|
|
|
|
-biginteger math::operator+(biginteger const & rhs, biginteger const & lhs) {
|
|
|
- if (lhs == biginteger::ZERO) { return rhs; }
|
|
|
- else if (rhs == biginteger::ZERO) { return lhs; }
|
|
|
- if (rhs.is_negative == lhs.is_negative) {
|
|
|
- return {rhs.is_negative, detail::add(rhs.data, lhs.data)};
|
|
|
- } else {
|
|
|
- auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
- if (cmp == 0) {
|
|
|
- return biginteger::ZERO;
|
|
|
- } else if (cmp > 0) {
|
|
|
- return {rhs.is_negative, detail::subtract_nounderflow(rhs.data, lhs.data)};
|
|
|
- } else {
|
|
|
- return {lhs.is_negative, detail::subtract_nounderflow(lhs.data, rhs.data)};
|
|
|
- }
|
|
|
- }
|
|
|
+biginteger math::operator+(biginteger rhs, biginteger const & lhs) {
|
|
|
+ return rhs += lhs;
|
|
|
}
|
|
|
|
|
|
-biginteger math::operator-(biginteger const & rhs, biginteger const & lhs) {
|
|
|
- if (lhs == biginteger::ZERO) { return rhs; }
|
|
|
- else if (rhs == biginteger::ZERO) { return -lhs; }
|
|
|
- if (rhs.is_negative != lhs.is_negative) {
|
|
|
- return {rhs.is_negative, detail::add(rhs.data, lhs.data)};
|
|
|
- } else {
|
|
|
- auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
- if (cmp == 0) {
|
|
|
- return biginteger::ZERO;
|
|
|
- } else if (cmp > 0) {
|
|
|
- return {rhs.is_negative, detail::subtract_nounderflow(rhs.data, lhs.data)};
|
|
|
- } else {
|
|
|
- return {!lhs.is_negative, detail::subtract_nounderflow(lhs.data, rhs.data)};
|
|
|
- }
|
|
|
- }
|
|
|
+biginteger math::operator-(biginteger rhs, biginteger const & lhs) {
|
|
|
+ return rhs -= lhs;
|
|
|
}
|
|
|
|
|
|
biginteger math::operator*(biginteger const & rhs, biginteger const & lhs) {
|
|
|
@@ -169,10 +173,11 @@ biginteger math::operator%(biginteger const & rhs, biginteger const & lhs) {
|
|
|
auto data = detail::divide(rhs.data, lhs.data).second;
|
|
|
if (detail::compare(data, {0}) == 0) { return biginteger::ZERO; }
|
|
|
else if (rhs.is_negative != lhs.is_negative) {
|
|
|
- return {lhs.is_negative, detail::subtract_nounderflow(lhs.data, data)};
|
|
|
- } else {
|
|
|
- return {lhs.is_negative, std::move(data)};
|
|
|
+ auto tmp = lhs.data;
|
|
|
+ swap(data, tmp);
|
|
|
+ detail::subtract_nounderflow(data, tmp);
|
|
|
}
|
|
|
+ return {lhs.is_negative, std::move(data)};
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -191,7 +196,7 @@ namespace detail {
|
|
|
}
|
|
|
#undef IMPL_COMPARE
|
|
|
|
|
|
- void add_into(data_type & rhs, data_type const & lhs) {
|
|
|
+ void add(data_type & rhs, data_type const & lhs) {
|
|
|
rhs.resize(std::max(rhs.size(), lhs.size())+1);
|
|
|
auto const lbnd = lhs.size(), ubnd = rhs.size() - 1;
|
|
|
// Add
|
|
|
@@ -208,12 +213,7 @@ namespace detail {
|
|
|
if (rhs[ubnd] == 0) { rhs.pop_back(); }
|
|
|
}
|
|
|
|
|
|
- data_type add(data_type rhs, data_type const & lhs) {
|
|
|
- add_into(rhs, lhs);
|
|
|
- return rhs;
|
|
|
- }
|
|
|
-
|
|
|
- void subtract_from(data_type & rhs, data_type const & lhs) {
|
|
|
+ void subtract_nounderflow(data_type & rhs, data_type const & lhs) {
|
|
|
size_t const rbnd = rhs.size(), lbnd = lhs.size();
|
|
|
// Subtract
|
|
|
for (size_t i = 0; i < lbnd; ++i) {
|
|
|
@@ -229,11 +229,6 @@ namespace detail {
|
|
|
if (rhs[rbnd-1] == 0 && rbnd > 1) { rhs.pop_back(); }
|
|
|
}
|
|
|
|
|
|
- data_type subtract_nounderflow(data_type rhs, data_type const & lhs) {
|
|
|
- subtract_from(rhs, lhs);
|
|
|
- return rhs;
|
|
|
- }
|
|
|
-
|
|
|
data_type multiply(data_type const & rhs, data_type const & lhs) {
|
|
|
if (compare(rhs, {1}) == 0) { return lhs; }
|
|
|
else if (compare(lhs, {1}) == 0) { return rhs; }
|
|
|
@@ -296,8 +291,8 @@ namespace detail {
|
|
|
data_type step{shift10({1}, powers[ipow], shift)};
|
|
|
data_type value{shift10(divisor, powers[ipow], shift)};
|
|
|
do {
|
|
|
- subtract_from(remainder, value);
|
|
|
- add_into(accum, step);
|
|
|
+ subtract_nounderflow(remainder, value);
|
|
|
+ add(accum, step);
|
|
|
} while (detail::compare(remainder, value) >= 0);
|
|
|
} while (detail::compare(remainder, divisor) >= 0);
|
|
|
return { std::move(accum), std::move(remainder) };
|