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::cast_to_int64(int64_t &i64) const { int ret = OB_SUCCESS; i64 = 0; bool is_neg = is_negative(); ObNumber pos_clone = *this; if (is_neg) { negate(*this, pos_clone); } ObNumber remainder; int vscale = vscale_; int digits[DOUBLE_PRECISION_NDIGITS]; int digit_idx = DOUBLE_PRECISION_NDIGITS - 1; while (!pos_clone.is_zero()) { div_uint32(pos_clone, 10, pos_clone, remainder); if (vscale > 0) { vscale--; } else { OB_ASSERT(digit_idx >= 0); if (remainder.is_zero()) { digits[digit_idx--] = 0; } else { OB_ASSERT(1 == remainder.nwords_); OB_ASSERT(remainder.words_[0] < 10 && remainder.words_[0] > 0); digits[digit_idx--] = remainder.words_[0]; } } // end while } OB_ASSERT(digit_idx >= -1); for (int i = digit_idx + 1; i < DOUBLE_PRECISION_NDIGITS; ++i) { i64 = i64 * 10 + digits[i]; } if (is_neg) { i64 = -i64; } return ret; }
bool ObObj::is_true() const { bool ret = false; switch (get_type()) { case ObBoolType: ret = value_.bool_val; break; case ObVarcharType: ret = (val_len_ > 0); break; case ObIntType: ret = (value_.int_val != 0); break; case ObDecimalType: { ObNumber dec; bool is_add = false; if (OB_SUCCESS == get_decimal(dec, is_add)) { ret = !dec.is_zero(); } break; } case ObFloatType: ret = (fabsf(value_.float_val) > FLOAT_EPSINON); break; case ObDoubleType: ret = (fabs(value_.double_val) > DOUBLE_EPSINON); break; case ObDateTimeType: case ObPreciseDateTimeType: case ObCreateTimeType: case ObModifyTimeType: { int64_t ts1 = 0; get_timestamp(ts1); ret = (0 != ts1); break; } default: break; } return ret; }
int ObNumber::compare(const ObNumber &other) const { int ret = 0; ObNumber res; if (OB_SUCCESS != this->sub(other, res)) { // return 0 even if error occur } else if (res.is_negative()) { ret = -1; } else if (!res.is_zero()) { ret = 1; } 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; }
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); } }
int64_t ObNumber::to_string(char* buf, const int64_t buf_len) const { int64_t pos = 0; OB_ASSERT(nwords_ <= MAX_NWORDS); OB_ASSERT(nwords_ > 0); char inner_buf[MAX_PRINTABLE_SIZE]; ObNumber clone; bool is_neg = is_negative(); if (is_neg) { negate(*this, clone); } else { clone = *this; } ObNumber remainder; int i = MAX_PRINTABLE_SIZE; while (!clone.is_zero()) { div_uint32(clone, 10, clone, remainder); if (remainder.is_zero()) { inner_buf[--i] = '0'; } else { OB_ASSERT(1 == remainder.nwords_); OB_ASSERT(remainder.words_[0] < 10 && remainder.words_[0] > 0); inner_buf[--i] = static_cast<char> ('0' + remainder.words_[0]); } OB_ASSERT(0 < i); } // end while int64_t dec_digits_num = MAX_PRINTABLE_SIZE - i; if (0 == dec_digits_num) { databuff_printf(buf, buf_len, pos, "0"); } else { if (is_neg) { databuff_printf(buf, buf_len, pos, "-"); } if (clone.vscale_ >= dec_digits_num) { // 0.0...0xxx databuff_printf(buf, buf_len, pos, "0."); for (int j = 0; j < clone.vscale_ - dec_digits_num; ++j) { databuff_printf(buf, buf_len, pos, "0"); } if (NULL != buf && 0 <= pos && dec_digits_num < buf_len - pos) { memcpy(buf + pos, inner_buf + i, dec_digits_num); pos += dec_digits_num; buf[pos] = '\0'; } } else { if (NULL != buf && 0 <= pos && dec_digits_num - clone.vscale_ < buf_len - pos) { memcpy(buf + pos, inner_buf + i, dec_digits_num - clone.vscale_); // digits before the point pos += dec_digits_num - clone.vscale_; } if (clone.vscale_ > 0) { if (NULL != buf && 0 <= pos && 1 + clone.vscale_ < buf_len - pos) { buf[pos++] = '.'; memcpy(buf + pos, inner_buf + i + dec_digits_num - clone.vscale_, clone.vscale_); // digits after the point pos += clone.vscale_; } } if (NULL != buf && 0 <= pos && 0 < buf_len - pos) { buf[pos] = '\0'; } } } OB_ASSERT(pos <= buf_len); return pos; }
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 } }