|
|
@@ -153,7 +153,27 @@ biginteger math::operator/(biginteger const & rhs, biginteger const & lhs) {
|
|
|
bool is_neg = rhs.is_negative != lhs.is_negative;
|
|
|
if (cmp < 0) { return biginteger::ZERO; }
|
|
|
else if (cmp == 0) { return {is_neg, {1}}; }
|
|
|
- else { return {is_neg, detail::divide(rhs.data, lhs.data)}; }
|
|
|
+ else { return {is_neg, detail::divide(rhs.data, lhs.data).first}; }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+biginteger math::operator%(biginteger const & rhs, biginteger const & lhs) {
|
|
|
+ if (lhs == biginteger::ZERO) { throw std::domain_error("cannot divide by 0"); }
|
|
|
+ else if (rhs == biginteger::ZERO || lhs == biginteger::ONE ||
|
|
|
+ lhs == biginteger::NEGATIVE_ONE) { return biginteger::ZERO; }
|
|
|
+ else {
|
|
|
+ auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
+ if (cmp < 0) { return rhs; }
|
|
|
+ else if (cmp == 0) { return biginteger::ZERO; }
|
|
|
+ else {
|
|
|
+ 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)};
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -266,11 +286,11 @@ namespace detail {
|
|
|
|
|
|
int32_t powers[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
|
|
|
|
|
|
- data_type divide(data_type remainder, data_type const & divisor) {
|
|
|
+ std::pair<data_type, data_type> divide(data_type remainder, data_type const & divisor) {
|
|
|
data_type accum{0};
|
|
|
auto const dig = digits(divisor);
|
|
|
do {
|
|
|
- auto const diff = digits(remainder) - dig - 1;
|
|
|
+ auto const diff = std::max(1UL, digits(remainder) - dig) - 1;
|
|
|
auto const shift = diff / biginteger::SEG_DIGITS;
|
|
|
auto const ipow = diff - (shift * biginteger::SEG_DIGITS);
|
|
|
data_type step{shift10({1}, powers[ipow], shift)};
|
|
|
@@ -280,7 +300,7 @@ namespace detail {
|
|
|
add_into(accum, step);
|
|
|
} while (detail::compare(remainder, value) >= 0);
|
|
|
} while (detail::compare(remainder, divisor) >= 0);
|
|
|
- return accum;
|
|
|
+ return { std::move(accum), std::move(remainder) };
|
|
|
}
|
|
|
}
|
|
|
|