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::negate(ObNumber &res) const { int ret = OB_SUCCESS; if (this->nwords_ >= MAX_NWORDS) { jlog(WARNING, "value out of range to do negate"); ret = JD_VALUE_OUT_OF_RANGE; } else { res = *this; res.extend_words(static_cast<int8_t> (this->nwords_ + 1)); negate(res, res); res.remove_leading_zeroes(); } return ret; }
int ObNumber::round_to(int8_t precision, int8_t scale, int8_t &nwords, int8_t &vscale, uint32_t *words) const { OB_ASSERT(precision >= scale && 0 <= scale && NULL != words); int ret = OB_SUCCESS; ObNumber clone = *this; bool is_neg = is_negative(); if (is_neg) { negate(clone, clone); } if (clone.vscale_ > scale) { clone.right_shift(static_cast<int8_t> (clone.vscale_ - scale)); clone.remove_leading_zeroes(); } ObNumber clone_clone = clone; int8_t vprec = 0; ObNumber remainder; while (!clone_clone.is_zero()) { div_uint32(clone_clone, 10, clone_clone, remainder); clone_clone.remove_leading_zeroes(); ++vprec; } if (vprec > precision) { ret = JD_VALUE_OUT_OF_RANGE; jlog(WARNING, "value is not representable with the precision and scale, p=%hhd s=%hhd vp=%hhd vs=%hhd", precision, scale, vprec, this->vscale_); } else { if (is_neg) { negate(clone, clone); } nwords = clone.nwords_; vscale = clone.vscale_; for (int8_t i = 0; i < clone.nwords_; ++i) { words[i] = clone.words_[i]; } } 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; }