|
@@ -21,6 +21,7 @@ namespace detail {
|
|
|
data_type add(data_type 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);
|
|
data_type subtract_nounderflow(data_type rhs, data_type const & lhs);
|
|
|
data_type multiply(data_type const & rhs, data_type const & lhs);
|
|
data_type multiply(data_type const & rhs, data_type const & lhs);
|
|
|
|
|
+ data_type divide(data_type remainder, data_type const & divisor);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void swap(biginteger & rhs, biginteger && lhs) {
|
|
static void swap(biginteger & rhs, biginteger && lhs) {
|
|
@@ -92,10 +93,10 @@ biginteger & operator*=(biginteger & rhs, biginteger const & lhs) {
|
|
|
return rhs;
|
|
return rhs;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-//biginteger & operator/=(biginteger & rhs, biginteger const & lhs) {
|
|
|
|
|
-// swap(rhs, rhs / lhs);
|
|
|
|
|
-// return rhs;
|
|
|
|
|
-//}
|
|
|
|
|
|
|
+biginteger & operator/=(biginteger & rhs, biginteger const & lhs) {
|
|
|
|
|
+ swap(rhs, rhs / lhs);
|
|
|
|
|
+ return rhs;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
biginteger biginteger::operator-() const {
|
|
biginteger biginteger::operator-() const {
|
|
|
return (*this) * NEGATIVE_ONE;
|
|
return (*this) * NEGATIVE_ONE;
|
|
@@ -142,6 +143,20 @@ biginteger math::operator*(biginteger const & rhs, biginteger const & lhs) {
|
|
|
return {rhs.is_negative != lhs.is_negative, detail::multiply(rhs.data, lhs.data)};
|
|
return {rhs.is_negative != lhs.is_negative, detail::multiply(rhs.data, lhs.data)};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+biginteger math::operator/(biginteger const & rhs, biginteger const & lhs) {
|
|
|
|
|
+ if (lhs == biginteger::ZERO) { throw 0; }
|
|
|
|
|
+ else if (rhs == biginteger::ZERO) { return biginteger::ZERO; }
|
|
|
|
|
+ else if (detail::compare(lhs.data, {1}) == 0) {
|
|
|
|
|
+ return {rhs.is_negative != lhs.is_negative, biginteger::data_type{rhs.data}};
|
|
|
|
|
+ } else {
|
|
|
|
|
+ auto cmp = detail::compare(rhs.data, lhs.data);
|
|
|
|
|
+ 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)}; }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
namespace detail {
|
|
namespace detail {
|
|
|
#define IMPL_COMPARE(expr) \
|
|
#define IMPL_COMPARE(expr) \
|
|
|
if (rhs expr < lhs expr) return -1; \
|
|
if (rhs expr < lhs expr) return -1; \
|
|
@@ -227,6 +242,46 @@ namespace detail {
|
|
|
while (rval.back() == 0 && rval.size() > 1) { rval.pop_back(); }
|
|
while (rval.back() == 0 && rval.size() > 1) { rval.pop_back(); }
|
|
|
return rval;
|
|
return rval;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ data_type shift10(data_type const & data, int32_t pow, size_t shift) {
|
|
|
|
|
+ size_t const bnd = data.size();
|
|
|
|
|
+ data_type rval(bnd + shift + 1);
|
|
|
|
|
+ for (size_t i = 0; i < bnd; ++i) {
|
|
|
|
|
+ int64_t product = static_cast<int64_t>(data[i]) * static_cast<int64_t>(pow);
|
|
|
|
|
+ int64_t overflow = product / biginteger::OVER_SEG;
|
|
|
|
|
+ rval[i+shift] += static_cast<int32_t>(product - (overflow * biginteger::OVER_SEG));
|
|
|
|
|
+ rval[i+shift+1] += static_cast<int32_t>(overflow);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (rval.back() == 0 && rval.size() > 1) { rval.pop_back(); }
|
|
|
|
|
+ return rval;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size_t digits(int32_t val) {
|
|
|
|
|
+ return val == 0 ? 1 : static_cast<size_t>(floor(log10(val))) + 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size_t digits(data_type const & data) {
|
|
|
|
|
+ return biginteger::SEG_DIGITS * (data.size()-1) + digits(data.back());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int32_t powers[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
|
|
|
|
|
+
|
|
|
|
|
+ data_type divide(data_type remainder, data_type const & divisor) {
|
|
|
|
|
+ data_type accum{0};
|
|
|
|
|
+ auto const dig = digits(divisor);
|
|
|
|
|
+ while (detail::compare(remainder, divisor) >= 0) {
|
|
|
|
|
+ auto const diff = 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)};
|
|
|
|
|
+ data_type value{shift10(divisor, powers[ipow], shift)};
|
|
|
|
|
+ do {
|
|
|
|
|
+ subtract_from(remainder, value);
|
|
|
|
|
+ add_into(accum, step);
|
|
|
|
|
+ } while (detail::compare(remainder, value) >= 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ return accum;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool math::operator==(biginteger const & rhs, biginteger const & lhs) {
|
|
bool math::operator==(biginteger const & rhs, biginteger const & lhs) {
|