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; }
void ObNumber::knuth_div_unsigned(const uint32_t *dividend, const ObNumber &divisor, ObNumber "ient, int8_t qidx, ObNumber &remainder) { OB_ASSERT(divisor.words_[divisor.nwords_ - 1] >= HALF_BASE); // (BASE ^ divisor_n)/2 <= divisor OB_ASSERT(0 <= qidx && qidx < MAX_NWORDS); ObNumber cdividend; cdividend.nwords_ = static_cast<int8_t> (divisor.nwords_ + 1); for (int8_t i = 0; i < cdividend.nwords_; ++i) { cdividend.words_[i] = dividend[i]; } ObNumber base; base.from(BASE); ObNumber p; mul_words(base, divisor, p); p.remove_leading_zeroes_unsigned(); int cmp = compare_words_unsigned(cdividend, p); if (cmp >= 0) { sub_words_unsigned(cdividend, p, cdividend); knuth_div_unsigned(cdividend.words_, divisor, quotient, qidx, remainder); // recursively called at most once quotient.words_[qidx + 1] = 1; } else { int8_t n = divisor.nwords_; uint64_t q = (UBASE * dividend[n] + dividend[n - 1]) / divisor.words_[n - 1]; if (q >= UBASE) { q = UBASE - 1; } ObNumber Q; Q.from(q); ObNumber T; mul_words(Q, divisor, T); T.remove_leading_zeroes_unsigned(); for (int i = 0; i < 2; ++i) { cmp = compare_words_unsigned(T, cdividend); if (cmp > 0) { Q.from(--q); sub_words_unsigned(T, divisor, T); } else { break; } } // end for if (Q.nwords_ == 1) { quotient.words_[qidx] = Q.words_[0]; } else { OB_ASSERT(Q.is_zero()); quotient.words_[qidx] = 0; } sub_words_unsigned(cdividend, T, remainder); } }