inline void ObNumber::div_uint32(const ObNumber ÷nd, uint32_t divisor, ObNumber "ient, ObNumber &remainder) { OB_ASSERT(0 < dividend.nwords_); OB_ASSERT(MAX_NWORDS >= dividend.nwords_); OB_ASSERT(0 < divisor); int64_t carry = 0; for (int i = dividend.nwords_ - 1; i >= 0; --i) { carry = carry * BASE + dividend.words_[i]; quotient.words_[i] = static_cast<uint32_t> (carry / divisor); carry = carry % divisor; } quotient.nwords_ = dividend.nwords_; quotient.remove_leading_zeroes(); if (0 == carry) { remainder.set_zero(); // remainder is zero } else { remainder.words_[0] = static_cast<uint32_t> (carry); remainder.nwords_ = 1; } }
int ObNumber::div(const ObNumber &other, ObNumber &res) const { int ret = OB_SUCCESS; res.set_zero(); if (other.is_zero()) { jlog(WARNING, "divisor is zero"); ret = JD_DIVISION_BY_ZERO; } else if (!this->is_zero()) { res.vscale_ = QUOTIENT_SCALE; ObNumber dividend = *this; ObNumber divisor = other; ObNumber remainder; bool res_is_neg = false; if (dividend.is_negative()) { negate(dividend, dividend); res_is_neg = true; } if (dividend.vscale_ > DOUBLE_PRECISION_NDIGITS) { dividend.round_fraction_part(DOUBLE_PRECISION_NDIGITS); } if (divisor.vscale_ > SINGLE_PRECISION_NDIGITS) { divisor.round_fraction_part(SINGLE_PRECISION_NDIGITS); } if (dividend.vscale_ < divisor.vscale_ || res.vscale_ > dividend.vscale_ - divisor.vscale_) { if (OB_SUCCESS != (ret = dividend.left_shift(static_cast<int8_t> (res.vscale_ + divisor.vscale_ - dividend.vscale_), true))) { jlog(WARNING, "left shift overflow, err=%d res_vscale=%hhd other_vscale=%hhd this_vscale=%hhd", ret, res.vscale_, divisor.vscale_, dividend.vscale_); } } if (OB_LIKELY(OB_SUCCESS == ret)) { if (divisor.is_negative()) { negate(divisor, divisor); res_is_neg = !res_is_neg; } divisor.remove_leading_zeroes_unsigned(); div_words(dividend, divisor, res, remainder); if (OB_UNLIKELY(res_is_neg)) { negate(res, res); } res.remove_leading_zeroes(); } } return ret; }
int ObNumber::add(const ObNumber &other, ObNumber &res) const { int ret = OB_SUCCESS; res.set_zero(); ObNumber n1 = *this; ObNumber n2 = other; if (n1.vscale_ > SINGLE_PRECISION_NDIGITS) { n1.round_fraction_part(SINGLE_PRECISION_NDIGITS); } if (n2.vscale_ > SINGLE_PRECISION_NDIGITS) { n2.round_fraction_part(SINGLE_PRECISION_NDIGITS); } int8_t res_nwords = static_cast<int8_t> (std::max(n1.nwords_, n2.nwords_) + 1); if (res_nwords > MAX_NWORDS) { jlog(WARNING, "number out of range"); ret = JD_VALUE_OUT_OF_RANGE; } else { n1.extend_words(res_nwords); n2.extend_words(res_nwords); } if (n1.vscale_ > n2.vscale_) { ret = n2.left_shift(static_cast<int8_t> (n1.vscale_ - n2.vscale_), false); } else if (n1.vscale_ < n2.vscale_) { ret = n1.left_shift(static_cast<int8_t> (n2.vscale_ - n1.vscale_), false); } if (OB_SUCCESS == ret) { add_words(n1, n2, res); res.remove_leading_zeroes(); } return ret; }
int ObNumber::mul(const ObNumber &other, ObNumber &res) const { int ret = OB_SUCCESS; res.set_zero(); if (!this->is_zero() && !other.is_zero()) { ObNumber multiplicand = *this; ObNumber multiplier = other; bool res_is_neg = false; if (multiplicand.is_negative()) { negate(multiplicand, multiplicand); res_is_neg = true; } if (multiplier.is_negative()) { negate(multiplier, multiplier); res_is_neg = !res_is_neg; } if (multiplicand.vscale_ > SINGLE_PRECISION_NDIGITS) { multiplicand.round_fraction_part(SINGLE_PRECISION_NDIGITS); } if (multiplier.vscale_ > SINGLE_PRECISION_NDIGITS) { multiplier.round_fraction_part(SINGLE_PRECISION_NDIGITS); } res.vscale_ = static_cast<int8_t> (multiplicand.vscale_ + multiplier.vscale_); ret = mul_words(multiplicand, multiplier, res); res.remove_leading_zeroes(); if (res_is_neg) { negate(res, res); } } return ret; }
inline void ObNumber::div_words(const ObNumber ÷nd, const ObNumber &divisor, ObNumber "ient, ObNumber &remainder) { OB_ASSERT(!dividend.is_zero()); OB_ASSERT(!divisor.is_zero()); OB_ASSERT(0 < dividend.nwords_ && dividend.nwords_ <= MAX_NWORDS); OB_ASSERT(0 < divisor.nwords_ && divisor.nwords_ <= MAX_NWORDS); if (1 == divisor.nwords_) { // fast algorithm div_uint32(dividend, divisor.words_[0], quotient, remainder); } else { // Knuth's algorithm, Volumn 2, Section 4.3, Page 235 ObNumber cdivisor; ObNumber cdividend; if (divisor.words_[divisor.nwords_ - 1] < HALF_BASE) { // make sure (BASE ^ n)/2 <= divisor uint32_t factor = static_cast<uint32_t> (BASE / (divisor.words_[divisor.nwords_ - 1] + 1)); mul_uint32(divisor, factor, cdivisor, true); mul_uint32(dividend, factor, cdividend, true); OB_ASSERT(cdivisor.words_[cdivisor.nwords_ - 1] >= HALF_BASE); } else { cdividend = dividend; cdivisor = divisor; } if (cdividend.nwords_ < cdivisor.nwords_) // include the case when dividend is zero { quotient.set_zero(); remainder = dividend; } else if (cdividend.nwords_ == cdivisor.nwords_) { int cmp = compare_words_unsigned(cdividend, cdivisor); if (cmp < 0) { quotient.set_zero(); remainder = dividend; } else { quotient.nwords_ = 1; quotient.words_[0] = 1; sub_words_unsigned(cdividend, cdivisor, remainder); } } else // dividend.nwords_ >= 1 + divosor.nwords_ { quotient.nwords_ = static_cast<int8_t> (cdividend.nwords_ - cdivisor.nwords_ + 1); memset(quotient.words_, 0, sizeof (quotient.words_)); for (int8_t i = static_cast<int8_t> (cdividend.nwords_ - cdivisor.nwords_ - 1); i >= 0; --i) { knuth_div_unsigned(&cdividend.words_[i], cdivisor, quotient, i, remainder); for (int8_t j = 0; j < cdivisor.nwords_; ++j) { cdividend.words_[i + j] = remainder.words_[j]; } } } } if (quotient.nwords_ > 0 && static_cast<int64_t> (quotient.words_[quotient.nwords_ - 1]) >= HALF_BASE) { quotient.words_[quotient.nwords_++] = 0; // quotient is always positive } if (remainder.nwords_ > 0 && static_cast<int64_t> (remainder.words_[remainder.nwords_ - 1]) >= HALF_BASE) { remainder.words_[remainder.nwords_++] = 0; // remainder is always positive } }