/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX LIB #include "lib/number/ob_number_v2.h" #include "lib/ob_define.h" #include "lib/utility/utility.h" #include "lib/utility/serialization.h" #include "lib/worker.h" #include #include #include "lib/charset/ob_dtoa.h" #include #include "lib/oblog/ob_log_module.h" #include "lib/utility/ob_hang_fatal_error.h" namespace oceanbase { namespace common { using namespace lib; namespace number { const char* ObNumber::DIGIT_FORMAT = "%09u"; const char* ObNumber::BACK_DIGIT_FORMAT[DIGIT_LEN] = { "%09u", "%08u", "%07u", "%06u", "%05u", "%04u", "%03u", "%02u", "%01u", }; const int ObNumber::MIN_ROUND_DIGIT_COUNT[] = { ObNumber::FLOATING_SCALE / ObNumber::DIGIT_LEN, common::OB_MAX_NUMBER_PRECISION_INNER / ObNumber::DIGIT_LEN}; const char ObNumber::FLOATING_ZEROS[ObNumber::FLOATING_SCALE + 1] = "000000000000000000000000000000000000000000000000000000000000000000000000"; const ObNumber& ObNumber::get_pi() { // len, cap, flag, exp, sign static Desc desc(10, 10, 0, EXP_ZERO, POSITIVE); static uint32_t digits[] = { 3, 141592653, 589793238, 462643383, 279502884, 197169399, 375105820, 974944592, 307816406, 286208998}; static ObNumber pi(desc.desc_, reinterpret_cast(digits)); return pi; } const ObString NUMBER_ERRMSG("ERROR NUM"); // 9 byte DEFINE_SERIALIZE(ObNumber) { return serialization::encode_number_type(buf, buf_len, pos, d_, digits_); } DEFINE_DESERIALIZE(ObNumber) { int ret = OB_SUCCESS; if (OB_SUCC(serialization::decode_number_type(buf, data_len, pos, d_, digits_))) { d_.cap_ = d_.len_; } return ret; } DEFINE_GET_SERIALIZE_SIZE(ObNumber) { return serialization::encode_length_number_type(d_); } const ObNumber& ObNumber::get_positive_one() { struct Init { explicit Init(ObNumber& v) { static StackAllocator sa; v.from("1", sa); }; }; static ObNumber one; static Init init(one); return one; } const ObNumber& ObNumber::get_positive_zero_dot_five() { struct Init { explicit Init(ObNumber& v) { static StackAllocator sa; v.from("0.5", sa); }; }; static ObNumber zero_dot_five; static Init init(zero_dot_five); return zero_dot_five; } const ObNumber& ObNumber::get_zero() { struct Init { explicit Init(ObNumber& v) { v.set_zero(); }; }; static ObNumber one; static Init init(one); return one; } uint32_t* ObNumber::alloc_(IAllocator& allocator, const int64_t num, const lib::ObMemAttr* attr) { if (0 >= num) { digits_ = NULL; d_.cap_ = 0; } else if (NULL == (digits_ = (NULL != attr ? allocator.alloc(num * sizeof(uint32_t), *attr) : allocator.alloc(num * sizeof(uint32_t))))) { d_.cap_ = 0; } else { d_.cap_ = (uint8_t)num; } return digits_; } bool ObNumber::is_equal(const number::ObNumber::Desc& this_desc, const uint32_t* this_digits, const number::ObNumber::Desc& other_desc, const uint32_t* other_digits) { bool bret = false; if (this_desc.se_ == other_desc.se_ && this_desc.len_ == other_desc.len_) { bret = uint32equal(this_digits, other_digits, this_desc.len_); } return bret; } int ObNumber::compare(const number::ObNumber::Desc& this_desc, const uint32_t* this_digits, const number::ObNumber::Desc& other_desc, const uint32_t* other_digits) { int ret = 0; if (this_desc.se_ == other_desc.se_) { if (this_desc.len_ == other_desc.len_) { ret = uint32cmp(this_digits, other_digits, this_desc.len_); } else if (this_desc.len_ < other_desc.len_) { if (0 == (ret = uint32cmp(this_digits, other_digits, this_desc.len_))) { ret = -1; } } else { if (0 == (ret = uint32cmp(this_digits, other_digits, other_desc.len_))) { ret = 1; } } if (NEGATIVE == this_desc.sign_) { ret = -ret; } } else if (this_desc.se_ < other_desc.se_) { ret = -1; } else { ret = 1; } return ret; } template int ObNumber::from_integer_(const IntegerT value, IAllocator& allocator) { int ret = OB_SUCCESS; static const uint64_t MAX_DIGITS[3] = {1L, 1000000000L, 1000000000000000000L}; if (0 == value) { set_zero(); } else { Desc desc; uint64_t abs_val = 0; if (std::is_signed::value) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wabsolute-value" #endif abs_val = (uint64_t)std::labs(value); #ifdef __clang__ #pragma clang diagnostic pop #endif } else { abs_val = value; } uint64_t exp = 0; uint32_t digits[OB_MAX_INTEGER_DIGIT] = {0}; uint8_t idx = 0; uint8_t zero_cnt = 0; for (int i = 2; i >= 0; i--) { if (abs_val >= MAX_DIGITS[i]) { idx += zero_cnt; digits[idx++] = uint32_t(abs_val / MAX_DIGITS[i]); exp = std::max(exp, (uint64_t)i); abs_val %= MAX_DIGITS[i]; zero_cnt = 0; } else if (exp > 0) { zero_cnt++; } } desc.exp_ = ((uint8_t)exp + EXP_ZERO) & 0x7f; if (value >= 0) { desc.sign_ = POSITIVE; } else { desc.sign_ = NEGATIVE; desc.exp_ = 0x7f & (~desc.exp_); ++desc.exp_; } desc.len_ = idx; desc.cap_ = idx; uint32_t* digit_mem = NULL; if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * idx))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("fail to alloc obnumber digit memory", K(ret), K(digit_mem), K(idx)); } else { MEMCPY(digit_mem, digits, ITEM_SIZE(digits_) * idx); assign(desc.desc_, (uint32_t*)digit_mem); } } return ret; } int ObNumber::from_(const int64_t value, IAllocator& allocator) { return from_integer_(value, allocator); } int ObNumber::from_(const uint64_t value, IAllocator& allocator) { return from_integer_(value, allocator); } int ObNumber::from_(const char* str, IAllocator& allocator, int16_t* precision, int16_t* scale, const bool do_rounding) { int ret = OB_SUCCESS; int warning = OB_SUCCESS; int64_t length = (NULL == str) ? 0 : strlen(str); ret = from_(str, length, allocator, warning, NULL, precision, scale, NULL, do_rounding); if (OB_SUCCESS == ret && OB_SUCCESS != warning) { ret = warning; } return ret; } /* from_sci -- from scientific notation * * str -- IN, scientific notation string representation * length -- IN, the length of the input string * allocator -- IN, used to alloc ObNumber * precision -- OUT, precision of the converted result * scale -- OUT, scale of the converted result * This function converts a scientific notation string into the internal number format * It's more efficient to call from_ if the string is a normal numeric string */ int ObNumber::from_sci_(const char* str, const int64_t length, IAllocator& allocator, int& warning, int16_t* precision, int16_t* scale, const bool do_rounding) { int ret = OB_SUCCESS; char full_str[MAX_PRINTABLE_SIZE] = {0}; char digit_str[MAX_PRINTABLE_SIZE] = {0}; bool is_neg = false; int32_t nth = 0; int32_t i_nth = 0; int32_t i = 0; int32_t e_value = 0; int32_t valid_len = 0; int32_t dec_n_zero = 0; bool e_neg = false; bool as_zero = false; bool has_digit = false; char tmpstr[MAX_PRINTABLE_SIZE] = {0}; char cur = '\0'; if (OB_UNLIKELY(NULL == str || length <= 0)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(WARN, "invalid param", K(length), KP(str), K(ret)); } else { /* parse str like 1.2e3 * part 1:allow str like 000123=> 123(valid length is 3); if valid length >126, ignore the rest * part 2:if '.' exists, part 2 must not be empty: str like 1.e3 is illegal * part 3:part 3's value + length of part1 <= 126 * */ for (i = 0; i < length && isspace(str[i]); ++i) ; if ('-' == str[i]) { is_neg = true; full_str[nth++] = '-'; i++; } else if ('+' == str[i]) { i++; } /* 000123 -> 123 */ while ('0' == str[i] && i + 1 < length) { i++; has_digit = true; } cur = str[i]; while (i + 1 < length && cur <= '9' && cur >= '0') { if (i_nth < MAX_PRECISION) { digit_str[i_nth++] = cur; cur = str[++i]; has_digit = true; } else { /* ignore the rest */ i++; } valid_len++; } } if (OB_SUCC(ret) && cur == '.' && valid_len < MAX_PRECISION && i + 1 < length) { cur = str[++i]; if (0 == valid_len) { /* 0.000123 -> dec_n_zero = 3 */ while ('0' == cur && i + 1 < length) { valid_len--; dec_n_zero++; cur = str[++i]; has_digit = true; } } /* 1.23 0.0123 0.123 -> digit_str:'123' */ while (i + 1 < length && cur <= '9' && cur >= '0') { if (i_nth < MAX_PRECISION) { digit_str[i_nth++] = cur; } else { /* ignore the rest */ } cur = str[++i]; if (0 >= valid_len) { valid_len--; } } } if (OB_SUCC(ret) && (has_digit || 0 < i_nth) && ('e' == cur || 'E' == cur) && is_valid_sci_tail_(str, length, i)) { LOG_DEBUG("ObNumber from sci", K(ret), K(i), K(cur), K(is_neg), K(nth), K(digit_str), K(i_nth), K(valid_len), K(dec_n_zero)); if (0 == i || i >= length - 1) { if (i_nth > 0) { memcpy(full_str + nth, digit_str, i_nth); nth += i_nth; } warning = OB_INVALID_NUMERIC; } else if (0 == valid_len || 0 == i_nth) { // `i_nth = 0` means all digits are zero. /* ignore e's value; only do the check*/ cur = str[++i]; if ('-' == cur || '+' == cur) { if (i < length - 1) { cur = str[++i]; } } if (cur <= '9' && cur >= '0') { cur = str[++i]; while (i < length && cur <= '9' && cur >= '0') { cur = str[++i]; } } else { /* 0e */ ret = OB_INVALID_NUMERIC; LOG_WARN("Number from sci invalid exponent", K(ret), K(cur), K(i)); } } else { cur = str[++i]; switch (cur) { case '-': e_neg = true; /* go through */ case '+': if (i < length - 1) { cur = str[++i]; } break; } /* Oracle max valid length of string is 255(exponent of the value is [-253, 255]) * exponent of number's legal range is [-130, 125] * so e_value's valid range can't larger than 3 digits */ int e_cnt = 0; while (i < length && cur <= '9' && cur >= '0') { if (e_cnt < 4) { e_value = e_neg ? (e_value * 10 - (cur - '0')) : (e_value * 10 + cur - '0'); } cur = str[++i]; e_cnt++; } LOG_DEBUG("ObNumber from sci E", K(warning), K(e_neg), K(e_cnt), K(e_value), K(valid_len), K(i)); if (0 == e_cnt) { warning = OB_INVALID_NUMERIC; e_value = 0; } if ((valid_len >= 0 && (e_value + valid_len <= MIN_SCI_SIZE)) || (valid_len < 0 && (e_value - dec_n_zero <= MIN_SCI_SIZE))) { as_zero = true; } else if (e_value + valid_len > MAX_SCI_SIZE) { ret = OB_NUMERIC_OVERFLOW; } else if (valid_len <= 0) { /* 0.01234e-5 */ if (e_value < 0) { nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "0.%0*d%s", 0 - e_value + dec_n_zero, 0, digit_str); LOG_DEBUG("ObNumber sci", K(tmpstr), K(nth), K(full_str), K(e_value), K(dec_n_zero), K(digit_str)); } else { if (dec_n_zero - e_value > 0) { /* 0.00012e2 -> 0.012 */ nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "0.%0*d%s", dec_n_zero - e_value, 0, digit_str); LOG_DEBUG("ObNumber sci", K(tmpstr), K(e_value), K(dec_n_zero)); } else if (e_value < dec_n_zero + i_nth) { /* 0.001234e4 -> 12.34 * e_value - dec_n_zero = 4 - 2 = 2 * fmt str: %2.s%s, digit_str, digit_str + 2*/ nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "%.*s.%s", e_value - dec_n_zero, digit_str, digit_str + e_value - dec_n_zero); LOG_DEBUG("ObNumber sci", K(tmpstr), K(full_str), K(nth), K(e_value), K(dec_n_zero), K(digit_str)); } else { /* 0.001234e8 -> 123400 * e_value - dec_n_zero - i_nth = 8 - 2 - 4 = 2 */ if (e_value - dec_n_zero - i_nth > 0) { snprintf(tmpstr, MAX_PRINTABLE_SIZE, "%0*d", e_value - dec_n_zero - i_nth, 0); } nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "%s%s", digit_str, tmpstr); LOG_DEBUG( "ObNumber sci", K(tmpstr), K(digit_str), K(full_str), K(nth), K(e_value), K(i_nth), K(dec_n_zero)); } } } else { if (e_value >= 0) { /* 12.34e5 -> 1234000 * e_value - (i_nth - valid_len) = 5 - (4 - 2) = 0*/ if (e_value - (i_nth - valid_len) > 0) { nth += snprintf( full_str + nth, MAX_PRINTABLE_SIZE - nth, "%s%0*d", digit_str, e_value - (i_nth - valid_len), 0); LOG_DEBUG("ObNumber sci", K(tmpstr), K(full_str), K(nth), K(e_value), K(i_nth), K(valid_len)); } else if (e_value - (i_nth - valid_len) == 0) { nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "%s", digit_str); LOG_DEBUG("ObNumber sci", K(full_str), K(nth), K(e_value), K(i_nth), K(valid_len)); } else { /* 12.345e2 -> 1234.5 * valid_len + e_value = 2 + 2 = 4 * fmt_str: %4.s, digit_str, digit_str + 4*/ nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "%.*s.%s", valid_len + e_value, digit_str, digit_str + valid_len + e_value); LOG_DEBUG( "ObNumber sci", K(valid_len + e_value), K(full_str), K(nth), K(e_value), K(digit_str), K(valid_len)); } } else { if (valid_len + e_value > 0) { /* 12.34e-1 -> 1.234 * valid_len + e_value = 2 - 1 = 1 * fmt_str: %1.s, digit_str, digit_str + 1*/ // sprintf(tmpstr, "%%%d.s.%%s", valid_len + e_value); nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "%.*s.%s", valid_len + e_value, digit_str, digit_str + valid_len + e_value); LOG_DEBUG( "ObNumber sci", K(valid_len + e_value), K(full_str), K(nth), K(e_value), K(digit_str), K(valid_len)); } else { /* 12.34e-4 -> 0.001234 * 0 - (valid_len + e_value) = 0 - (2 - 4) = 2 */ if (valid_len + e_value < 0) { snprintf(tmpstr, MAX_PRINTABLE_SIZE, "%0*d", 0 - (valid_len + e_value), 0); } nth += snprintf(full_str + nth, MAX_PRINTABLE_SIZE - nth, "0.%s%s", tmpstr, digit_str); LOG_DEBUG("ObNumber sci", K(tmpstr), K(full_str), K(nth), K(e_value), K(digit_str), K(valid_len)); } } } } if (OB_SUCC(ret) || !is_oracle_mode()) { LOG_DEBUG("Number from sci last ", K(cur), K(i), K(str + i), K(length), K(valid_len), K(ret), K(warning)); while (cur == ' ' && i < length - 1) { cur = str[++i]; } if (cur != ' ' && i <= length - 1) { warning = OB_INVALID_NUMERIC; LOG_WARN("invalid numeric string", K(ret), K(i), K(length), K(cur), "str", ObString(length, str)); } if ((OB_SUCCESS != warning) && is_oracle_mode() && OB_SUCC(ret)) { ret = warning; } else if (OB_FAIL(ret) && !is_oracle_mode()) { as_zero = true; // warning = OB_ERR_DOUBLE_TRUNCATED; warning = ret; ret = OB_SUCCESS; } if (OB_SUCC(ret)) { LOG_DEBUG("ObNumber sci final", K(ret), K(warning), K(full_str), K(nth), K(as_zero), K(e_neg), K(e_value), K(valid_len), K(i), K(i_nth)); if (as_zero || 0 == valid_len || 0 == i_nth) { full_str[0] = '0'; nth = 1; set_zero(); } else { int tmp_warning = OB_SUCCESS; ret = from_(full_str, nth, allocator, tmp_warning, NULL, precision, scale, NULL, do_rounding); if (OB_SUCC(ret) && OB_SUCCESS != warning) { warning = tmp_warning; } } } } } else { ret = from_(str, length, allocator, warning, NULL, precision, scale, NULL, do_rounding); } return ret; } int ObNumber::from_v1_(const char* str, const int64_t length, IAllocator& allocator, int& warning, ObNumberFmtModel* fmt, int16_t* precision, int16_t* scale, const lib::ObMemAttr* attr) { int ret = OB_SUCCESS; uint32_t digits[MAX_CALC_LEN]; ObNumberBuilder nb; nb.number_.set_digits(digits); nb.number_.d_.cap_ = MAX_CALC_LEN; if (OB_UNLIKELY(NULL == str || length <= 0)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(WARN, "invalid param", K(length), KP(str), K(ret)); } else if (OB_FAIL(nb.build(str, length, warning, fmt, precision, scale))) { LIB_LOG(WARN, "number build from fail", K(ret), K(length), "str", ObString(length, str)); } else if (OB_FAIL(is_oracle_mode() ? nb.number_.round_scale_oracle_(MAX_SCALE, true, precision, scale) : nb.number_.round_scale_(FLOATING_SCALE, true))) { LIB_LOG(WARN, "round scale fail", K(ret), K(length), "str", ObString(length, str)); } else if (OB_FAIL(exp_check_(nb.number_.get_desc()))) { LIB_LOG(WARN, "exponent precision check fail", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { set_zero(); ret = OB_SUCCESS; } } else if (0 == nb.number_.d_.len_) { set_zero(); } else if (OB_UNLIKELY(nb.number_.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; LIB_LOG(WARN, "out of range, ret = %d , length = %d", K(ret), K(nb.number_.d_.len_)); } else if (OB_ISNULL(digits_ = alloc_(allocator, nb.number_.d_.len_, attr))) { _OB_LOG(WARN, "alloc digits fail, length=%hhu", nb.number_.d_.len_); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits_, nb.number_.get_digits(), nb.number_.d_.len_ * ITEM_SIZE(digits_)); uint8_t tmp = d_.cap_; d_ = nb.number_.d_; d_.cap_ = tmp; } return ret; } int ObNumber::from_v2_(const char* str, const int64_t length, IAllocator& allocator, int& warning, ObNumberFmtModel* fmt, int16_t* precision, int16_t* scale, const lib::ObMemAttr* attr, const bool do_rounding) { int ret = OB_SUCCESS; uint32_t digits[MAX_CALC_LEN] = {}; ObNumberBuilder nb; nb.number_.set_digits(digits); nb.number_.d_.cap_ = MAX_CALC_LEN; if (OB_ISNULL(str) || OB_UNLIKELY(length <= 0)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(WARN, "invalid param", K(length), KP(str), K(ret)); } else if (OB_FAIL(nb.build_v2(str, length, warning, fmt, precision, scale))) { LIB_LOG(WARN, "number build from fail", K(ret), K(length), "str", ObString(length, str)); } else if (do_rounding && OB_FAIL(nb.number_.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { _LIB_LOG(WARN, "round scale fail, ret=%d str=[%.*s]", ret, static_cast(length), str); } else if (OB_FAIL(exp_check_(nb.number_.get_desc(), lib::is_oracle_mode()))) { LIB_LOG(WARN, "exponent precision check fail", K(nb.number_), K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { set_zero(); ret = OB_SUCCESS; } } else if (0 == nb.number_.d_.len_) { set_zero(); } else if (OB_UNLIKELY(nb.number_.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; LIB_LOG(WARN, "out of range", K(ret), K(nb.number_.d_.len_)); } else if (OB_ISNULL(digits_ = alloc_(allocator, nb.number_.d_.len_, attr))) { _OB_LOG(WARN, "alloc digits fail, length=%hhu", nb.number_.d_.len_); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits_, nb.number_.get_digits(), nb.number_.d_.len_ * ITEM_SIZE(digits_)); uint8_t tmp = d_.cap_; d_ = nb.number_.d_; d_.cap_ = tmp; } return ret; } /* * [start, floating_point-1] : int range * [floating_point+1, end-1] : decimal range */ int ObNumber::find_point_range_(const char* str, const int64_t length, int64_t& start_idx, int64_t& floating_point, int64_t& end_idx, bool& negative, int32_t& warning, int16_t* precision, int16_t* scale) { int ret = OB_SUCCESS; int64_t tmp_precision = 0; int64_t tmp_scale = 0; int64_t tmp_start_idx = 0; if (OB_UNLIKELY(NULL == str || length <= 0)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(WARN, "invalid param", K(length), K(str), K(ret)); } else { const char* str_ptr = str; const char* str_end = str + length; for (; str_ptr != str_end && isspace(*str_ptr); ++str_ptr) ; /* ignore leading space */ for (; str_ptr != str_end && isspace(*(str_end - 1)); --str_end) ; /* ignore tailer space */ if (OB_UNLIKELY(str_ptr == str_end)) { // empty string is enabled warning = OB_INVALID_NUMERIC; } else { /* check positive or negative */ if (*str_ptr == '+') { ++str_ptr; } else if (*str_ptr == '-') { ++str_ptr; negative = true; } for (; str_ptr != str_end && *str_ptr == '0'; ++str_ptr) ; /* ignore leading zero */ if (str_ptr == str_end) { // all zero cases: // start_idx should points to the last '0'. // start_idx and end_idx point to the same position, // so that the 'construct_digits_()' would generate // number '0' in the end start_idx = str_ptr - 1 - str; tmp_start_idx = start_idx; floating_point = start_idx; end_idx = start_idx; } else { start_idx = str_ptr - str; tmp_start_idx = ((*str_ptr == '.') ? (start_idx - 1) : start_idx); for (; str_ptr != str_end && ('0' <= *str_ptr && *str_ptr <= '9'); ++str_ptr) ; if (str_ptr != str_end && *str_ptr == '.') { /* find floating point */ int64_t non_zero_end = 0; floating_point = str_ptr - str; ++str_ptr; for (; str_ptr != str_end && ('0' <= *str_ptr && *str_ptr <= '9'); ++str_ptr) ; end_idx = str_ptr - str; } else { floating_point = str_ptr - str; end_idx = floating_point; } if (str_ptr != str_end) { warning = OB_INVALID_NUMERIC; } } } if (NULL != precision && NULL != scale) { *scale = static_cast((end_idx - floating_point >= 1) ? (end_idx - floating_point - 1) : 0); if (*scale > ObNumber::FLOATING_SCALE) { *scale = ObNumber::FLOATING_SCALE; } *precision = static_cast(floating_point - tmp_start_idx + *scale); tmp_precision = *precision; tmp_scale = *scale; } } const ObString tmp_string(length, str); LIB_LOG(DEBUG, "succ to find_point_range_", K(tmp_string), K(start_idx), K(tmp_start_idx), K(floating_point), K(end_idx), K(negative), K(ret), K(warning), K(tmp_precision), K(tmp_scale)); return ret; } int ObNumber::construct_digits_(const char* str, const int64_t start_idx, const int64_t floating_point, const int64_t end_idx, uint32_t* digits, int64_t& exp, int64_t& len) { int ret = OB_SUCCESS; const int64_t POWS[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000}; int64_t di_id = 0; int step = 0; bool has_integer_part = false; uint32_t* curr_digit = digits + di_id; if (start_idx < floating_point) { const char* str_ptr = str + start_idx; const char* str_end = str + floating_point; int integer_length = (floating_point - start_idx - 1) / ObNumber::MAX_STORE_LEN + 1; // = floor[(end - start_idx + 1) / MAX_STORE_LEN] step = (floating_point - start_idx - 1) % ObNumber::MAX_STORE_LEN + 1; for (; str_ptr < str_end && di_id < len; str_ptr += step, ++di_id, step = ObNumber::MAX_STORE_LEN) { *curr_digit = ObFastAtoi::atoi_positive_unchecked(str_ptr, str_ptr + step); // LIB_LOG(DEBUG, "push to construct_digits_", "di_id", di_id, "digit", *curr_digit, "curr_idx", str_ptr - // str, K(step)); ++curr_digit; } exp = integer_length - 1; has_integer_part = true; } if (di_id < len && floating_point + 1 < end_idx) { const char* str_ptr = str + floating_point + 1; const char* str_end = str + end_idx; if (!has_integer_part) { for (; str_ptr != str_end && *str_ptr == '0'; ++str_ptr) ; // ignore leading zero in decimal part int decimal_zero = ((str_ptr - str) - floating_point - 1) / ObNumber::MAX_STORE_LEN + 1; exp = -decimal_zero; step = ObNumber::MAX_STORE_LEN - ((str_ptr - str) - floating_point - 1) % ObNumber::MAX_STORE_LEN; } else { step = ObNumber::MAX_STORE_LEN; } for (; str_ptr < str_end && di_id < len; str_ptr += step, ++di_id, step = ObNumber::MAX_STORE_LEN) { if (str_ptr + step < str_end) { *curr_digit = ObFastAtoi::atoi_positive_unchecked(str_ptr, str_ptr + step); } else { *curr_digit = ObFastAtoi::atoi_positive_unchecked(str_ptr, str_end); *curr_digit *= POWS[step - (str_end - str_ptr)]; } // LIB_LOG(DEBUG, "push to construct_digits_", "di_id", di_id, "digit", *curr_digit, "curr_idx", str_ptr - // str, K(step)); ++curr_digit; } } curr_digit = digits + di_id - 1; while (curr_digit >= digits && 0 == *curr_digit) { --curr_digit; } len = (curr_digit >= digits ? (curr_digit - digits + 1) : 0); LIB_LOG(DEBUG, "succ to construct_digits_", K(exp), K(len)); return ret; } int ObNumber::from_v3_(const char* str, const int64_t length, IAllocator& allocator, int& warning, ObNumberFmtModel* fmt, int16_t* precision, int16_t* scale, const lib::ObMemAttr* attr, const bool do_rounding) { int ret = OB_SUCCESS; UNUSED(fmt); uint32_t digits[OB_CALC_BUFFER_SIZE] = {}; bool negative = false; int64_t start_idx = -1; int64_t floating_point = -1; int64_t end_idx = -1; int64_t exp = 0; int64_t len = OB_CALC_BUFFER_SIZE; Desc d; /* Step 1: find floating point and integer & decimal range */ if (OB_FAIL( find_point_range_(str, length, start_idx, floating_point, end_idx, negative, warning, precision, scale))) { LOG_WARN("find floating point and range error\n"); /* Step 2: construct digits with fixed length, ignore overflowed, return exp and len */ } else if (OB_FAIL(construct_digits_(str, start_idx, floating_point, end_idx, digits, exp, len))) { LOG_WARN("fail to construct digits\n"); /* Step 3: calc desc : promise exp and len are in range */ } else { d.desc_ = 0; d.sign_ = negative ? ObNumber::NEGATIVE : ObNumber::POSITIVE; d.len_ = (uint8_t)len; d.cap_ = (uint8_t)len; d.exp_ = 0x7f & (uint8_t)(EXP_ZERO + exp); if (d.sign_ == NEGATIVE) { d.exp_ = (0x7f & ~d.exp_) + 1; } } if (OB_SUCC(ret)) { d_.desc_ = d.desc_; if (OB_FAIL(exp_check_(d, lib::is_oracle_mode()))) { LOG_WARN("exponent precision check fail", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { set_zero(); ret = OB_SUCCESS; } } else if (0 == d.len_) { set_zero(); /* Step 5: construct ObNumber */ } else if (OB_ISNULL(digits_ = alloc_(allocator, d.len_, attr))) { ret = OB_ALLOCATE_MEMORY_FAILED; _OB_LOG(ERROR, "alloc digits fail, length=%hhu", d.len_); } else { MEMCPY(digits_, digits, d.len_ * sizeof(uint32_t)); /* Step 6: normalize to 72 digits and check */ if (do_rounding && OB_FAIL(round_scale_v3_(is_oracle_mode() ? (-MIN_SCI_SIZE) : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret)); } } } if (OB_FAIL(ret)) { set_zero(); } return ret; } int ObNumber::from_(const uint32_t desc, const ObCalcVector& vector, IAllocator& allocator) { int ret = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); ObCalcVector normalized_vector = vector; if (OB_FAIL(normalized_vector.normalize())) { LOG_WARN("normalized_vector.normalize() fails", K(ret)); } Desc d; d.desc_ = desc; d.len_ = (uint8_t)std::min(+MAX_STORE_LEN, normalized_vector.size()); if (OB_FAIL(ret)) { LOG_WARN("Previous normalize() fails", K(ret)); } else if (0 == d.len_) { set_zero(); } else if (OB_UNLIKELY(d.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)d.len_); } else if (OB_ISNULL(digits_ = alloc_(allocator, d.len_))) { LOG_WARN("alloc digits fail", K(d.len_)); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits_, normalized_vector.get_digits(), d.len_ * ITEM_SIZE(digits_)); d_.sign_ = d.sign_; d_.exp_ = d.exp_; if (OB_FAIL(normalize_(digits_, d.len_))) { _OB_LOG(WARN, "normalize [%s] fail, ret=%d", to_cstring(*this), ret); } else if (OB_FAIL(round_scale_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true))) { LOG_WARN("round scale fail", K(ret), K(*this)); } else if (OB_FAIL(exp_check_(d_, lib::is_oracle_mode()))) { LOG_WARN("exponent precision check fail", K(ret), K(*this)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { set_zero(); ret = OB_SUCCESS; } } else { // do nothing } } return ret; } int ObNumber::from_v2_(const uint32_t desc, const ObCalcVector& vector, IAllocator& allocator) { int ret = OB_SUCCESS; ObCalcVector normalized_vector = vector; if (OB_FAIL(normalized_vector.normalize())) { LOG_WARN("normalized_vector.normalize() fails", K(ret)); } Desc d; d.desc_ = desc; d.len_ = (uint8_t)std::min(+MAX_STORE_LEN, normalized_vector.size()); if (OB_FAIL(ret)) { LOG_WARN("Previous normalize() fails", K(ret)); } else if (0 == d.len_) { set_zero(); } else if (OB_UNLIKELY(d.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)d.len_); } else if (OB_ISNULL(digits_ = alloc_(allocator, d.len_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc digits fail", K(d.len_)); } else { MEMCPY(digits_, normalized_vector.get_digits(), d.len_ * ITEM_SIZE(digits_)); d_.sign_ = d.sign_; d_.exp_ = d.exp_; if (OB_FAIL(normalize_(digits_, d.len_))) { _OB_LOG(WARN, "normalize [%s] fail, ret=%d", to_cstring(*this), ret); } else if (OB_FAIL(round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(*this)); } else if (OB_FAIL(exp_check_(d_, lib::is_oracle_mode()))) { LOG_WARN("exponent precision check fail", K(ret), K(*this)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { set_zero(); ret = OB_SUCCESS; } } else { // do nothing } } return ret; } int ObNumber::from_( const int16_t precision, const int16_t scale, const char* str, const int64_t length, IAllocator& allocator) { int ret = OB_SUCCESS; int warning = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (OB_UNLIKELY(MIN_PRECISION > precision || MAX_PRECISION < precision || MIN_SCALE > scale || MAX_SCALE < scale || NULL == str || 0 >= length)) { LOG_WARN("invalid param", K(precision), K(scale), KP(str), K(length)); ret = OB_INVALID_ARGUMENT; } else { uint32_t digits[MAX_CALC_LEN]; ObNumberBuilder nb; nb.number_.set_digits(digits); nb.number_.d_.cap_ = MAX_CALC_LEN; if (OB_FAIL(nb.build(str, length, warning))) { _OB_LOG(WARN, "number build from fail, ret=%d str=[%.*s]", ret, (int)length, str); } else if (OB_FAIL(nb.number_.check_and_round(precision, scale))) { _OB_LOG(WARN, "check and round fail, ret=%d str=[%.*s]", ret, (int)length, str); } else if (0 == nb.number_.d_.len_) { set_zero(); } else if (OB_UNLIKELY(nb.number_.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)nb.number_.d_.len_); } else if (OB_ISNULL(digits_ = alloc_(allocator, nb.number_.d_.len_))) { LOG_WARN("alloc digits fail", K(nb.number_.d_.len_)); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits_, nb.number_.get_digits(), nb.number_.d_.len_ * ITEM_SIZE(digits_)); uint8_t tmp = d_.cap_; d_ = nb.number_.d_; d_.cap_ = tmp; } } if (OB_FAIL(ret)) { // pass } else if (OB_SUCCESS != warning) { ret = warning; } else { /* Do nothing */ } return ret; } int ObNumber::from_(const ObNumber& other, IAllocator& allocator) { int ret = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (&other == this) { // assign to self } else if (0 == other.d_.len_) { set_zero(); } else if (OB_UNLIKELY(other.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)other.d_.len_); } else if (OB_ISNULL(digits_ = alloc_(allocator, other.d_.len_))) { _OB_LOG(DEBUG, "alloc digits fail, length=%hhu", other.d_.len_); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits_, other.digits_, other.d_.len_ * ITEM_SIZE(digits_)); uint8_t tmp = d_.cap_; d_ = other.d_; d_.cap_ = tmp; } return ret; } int ObNumber::deep_copy(const ObNumber& other, IAllocator& allocator) { int ret = OB_SUCCESS; uint32_t* digits = NULL; if (&other == this) { // assign to self } else if (0 == other.d_.len_) { set_zero(); } else if (OB_UNLIKELY(other.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)other.d_.len_); } else if (OB_ISNULL(digits = alloc_(allocator, other.d_.len_))) { _OB_LOG(DEBUG, "alloc digits fail, length=%hhu", other.d_.len_); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits, other.digits_, other.d_.len_ * ITEM_SIZE(digits)); uint8_t tmp = d_.cap_; d_ = other.d_; d_.cap_ = tmp; digits_ = digits; OB_LOG(DEBUG, "deep_copy", K(other)); } return ret; } int ObNumber::deep_copy_v3(const ObNumber& other, ObIAllocator& allocator) { int ret = OB_SUCCESS; uint32_t* digits = NULL; if (&other == this) { // assign to self } else if (0 == other.d_.len_) { set_zero(); } else if (OB_UNLIKELY(other.d_.len_ > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; _OB_LOG(WARN, "out of range, ret = %d , length = %d", ret, (int)other.d_.len_); } else if (OB_ISNULL(digits = (uint32_t*)allocator.alloc(sizeof(uint32_t) * other.d_.len_))) { _OB_LOG(DEBUG, "alloc digits fail, length=%hhu", other.d_.len_); ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(digits, other.digits_, other.d_.len_ * ITEM_SIZE(digits)); uint8_t tmp = d_.cap_; d_ = other.d_; d_.cap_ = tmp; digits_ = digits; // OB_LOG(DEBUG, "deep_copy_v3", K(other)); } return ret; } int ObNumber::deep_copy_to_allocator_(ObIAllocator& allocator) { int ret = OB_SUCCESS; number::ObNumber tmp; if (OB_FAIL(tmp.from(*this, allocator))) { LOG_WARN("failed: depp copy *this to tmp with given allocator", KPC(this), K(tmp), K(ret)); } else { *this = tmp; } return ret; } int ObNumber::from_(const ObNumber& other, uint32_t* digits, uint8_t cap) { int ret = OB_SUCCESS; if (&other == this) { // assign to self } else if (0 == other.d_.len_) { set_zero(); } else if (OB_UNLIKELY(NULL == digits || cap < other.d_.len_)) { ret = OB_ERR_UNEXPECTED; } else { digits_ = digits; MEMCPY(digits_, other.digits_, other.d_.len_ * ITEM_SIZE(digits_)); d_ = other.d_; d_.cap_ = cap; } return ret; } int ObNumber::floor(const int64_t scale) { int ret = OB_SUCCESS; int int_len = 0; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (OB_UNLIKELY(0 != scale)) { LOG_WARN("invalid param", K(scale)); ret = OB_INVALID_ARGUMENT; } else if (is_zero()) { ret = OB_SUCCESS; } else if (OB_UNLIKELY(NULL == digits_ || 0 >= d_.len_)) { ret = OB_NOT_INIT; } else { if (POSITIVE == d_.sign_) { int_len = d_.se_ - POSITIVE_EXP_BOUNDARY; if (int_len >= 0) { int_len += 1; } else { int_len = -1; } } else if (NEGATIVE == d_.sign_) { int_len = NEGATIVE_EXP_BOUNDARY - d_.se_; if (int_len >= 0) { int_len += 1; } else { int_len = -1; } } else { /* Do nothing */ } if (int_len > 0 && int_len < d_.len_) { if (POSITIVE == d_.sign_) { for (int64_t i = int_len; i < d_.len_; ++i) { digits_[i] = 0; } } else if (NEGATIVE == d_.sign_) { for (int64_t i = int_len; i < d_.len_; ++i) { digits_[i] = 0; } for (int64_t i = int_len - 1; i >= 0; --i) { if ((BASE - 1) != digits_[i]) { digits_[i] += 1; break; } else { digits_[i] = 0; } } if (0 == digits_[0] && NEGATIVE == d_.sign_) { for (int64_t i = (int_len - 1); i >= 0; --i) { digits_[i + 1] = digits_[i]; } digits_[0] = 1; --d_.exp_; } } else { /* Do nothing */ } if (int_len < MAX_STORE_LEN) { d_.len_ = static_cast(int_len); } } else if (-1 == int_len && OB_SUCCESS == ret) { for (int64_t i = 0; i < d_.len_; ++i) { digits_[i] = 0; } if (POSITIVE == d_.sign_) { set_zero(); } else if (NEGATIVE == d_.sign_) { digits_[0] = 1; d_.se_ = 0x40; d_.len_ = 1; } } else { /* Do nothing */ } } return ret; } int ObNumber::ceil(const int64_t scale) { int ret = OB_SUCCESS; int int_len = 0; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (OB_UNLIKELY(0 != scale)) { LOG_WARN("invalid param", K(scale)); ret = OB_INVALID_ARGUMENT; } else if (is_zero()) { ret = OB_SUCCESS; } else if (OB_UNLIKELY(NULL == digits_ || 0 >= d_.len_)) { ret = OB_NOT_INIT; } else { if (POSITIVE == d_.sign_) { int_len = d_.se_ - POSITIVE_EXP_BOUNDARY; if (int_len >= 0) { int_len += 1; } else { int_len = -1; } } else if (NEGATIVE == d_.sign_) { int_len = NEGATIVE_EXP_BOUNDARY - d_.se_; if (int_len >= 0) { int_len += 1; } else { int_len = -1; } } else { /* Do nothing */ } if (int_len > 0 && int_len < d_.len_) { for (int64_t i = int_len; i < d_.len_; ++i) { digits_[i] = 0; } d_.len_ = static_cast(int_len); if (POSITIVE == d_.sign_) { for (int64_t i = int_len - 1; i >= 0; --i) { if ((BASE - 1) != digits_[i]) { digits_[i] += 1; break; } else { digits_[i] = 0; } } if (0 == digits_[0]) { // since int_len is less than len_, so the loop below is safe, // we won't get a buffer overflow problem. for (int64_t i = (int_len - 1); i >= 0; --i) { digits_[i + 1] = digits_[i]; } digits_[0] = 1; ++d_.len_; ++d_.exp_; } } } else if (int_len < 0) { for (int64_t i = 0; i < d_.len_; ++i) { digits_[i] = 0; } if (POSITIVE == d_.sign_) { digits_[0] = 1; d_.se_ = 0xc0; d_.len_ = 1; } else if (NEGATIVE == d_.sign_) { set_zero(); } } else { /* Do nothing */ } } return ret; } int ObNumber::trunc(const int64_t scale) { int ret = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (OB_UNLIKELY(MIN_SCALE > scale || MAX_SCALE < scale)) { LOG_WARN("invalid param", K(scale)); ret = OB_INVALID_ARGUMENT; } else if (is_zero()) { ret = OB_SUCCESS; } else if (OB_UNLIKELY(NULL == digits_ || 0 >= d_.len_)) { ret = OB_NOT_INIT; } else if (OB_FAIL(trunc_scale_(scale, false))) { LOG_WARN("trunc scale failed", K(*this), K(ret)); } else { LOG_DEBUG("trunc scale succ", K(*this), K(scale)); // do nothing } return ret; } int ObNumber::round_v1(const int64_t scale) { int ret = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (is_zero()) { ret = OB_SUCCESS; } else if (OB_UNLIKELY(NULL == digits_ || 0 >= d_.len_)) { ret = OB_NOT_INIT; } else if (is_oracle_mode()) { if (OB_FAIL(round_scale_oracle_(scale, false))) { //_OB_LOG(WARN, "Buffer overflow, %s", to_cstring(*this)); } } else { if (OB_UNLIKELY(MIN_SCALE > scale || MAX_SCALE < scale)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid param", K(scale), K(ret)); } else if (OB_FAIL(round_scale_(scale, false))) { //_OB_LOG(WARN, "Buffer overflow, %s", to_cstring(*this)); } else { // do nothing } } return ret; } int ObNumber::check_and_round(const int64_t precision, const int64_t scale) { int ret = OB_SUCCESS; ObTRecover recover_guard(*this, OB_SUCCESS, ret); if (is_zero()) { ret = OB_SUCCESS; } else if (OB_UNLIKELY(NULL == digits_ || 0 >= d_.len_)) { ret = OB_NOT_INIT; } else if (INT64_MAX != precision && OB_FAIL(round_scale_v3_(scale, false, false))) { //_OB_LOG(WARN, "Buffer overflow, %s", to_cstring(*this)); } else if (INT64_MAX != precision && INT64_MAX != scale && OB_FAIL(check_precision_(precision, scale))) { // _OB_LOG(WARN, "Precision overflow, %s", to_cstring(*this)); } else { // do nothing } return ret; } int64_t ObNumber::to_string(char* buffer, const int64_t length) const { int64_t pos = 0; if (d_.len_ > 0 && OB_ISNULL(digits_)) { databuff_printf(buffer, length, pos, "WARN the pointer is null"); } else { databuff_printf( buffer, length, pos, "\"sign=%hhu exp=%hhu se=0x%hhx len=%hhu digits=[", d_.sign_, d_.exp_, d_.se_, d_.len_); for (uint8_t i = 0; i < d_.len_; ++i) { databuff_printf(buffer, length, pos, "%u,", digits_[i]); } databuff_printf(buffer, length, pos, "]\""); } return pos; } bool ObNumber::is_valid_uint64(uint64_t& uint64) const { bool bret = false; uint64_t tmp_int_parts = 0; uint64_t tmp_decimal_parts = 0; if (OB_UNLIKELY(OB_SUCCESS != check_range(&bret, NULL, tmp_int_parts, tmp_decimal_parts))) { LOG_WARN("can't to check the param range", K(bret)); } else { uint64 = tmp_int_parts; bret = bret && (0 == tmp_decimal_parts); // Should not use if-test. } return bret; } bool ObNumber::is_valid_int64(int64_t& int64) const { bool bret = false; uint64_t tmp_int_parts = 0; uint64_t tmp_decimal_parts = 0; if (OB_UNLIKELY(OB_SUCCESS != check_range(NULL, &bret, tmp_int_parts, tmp_decimal_parts))) { LOG_WARN("can't to check the param range", K(bret)); } else { int64 = is_negative() ? (-1 * tmp_int_parts) : tmp_int_parts; bret = bret && (0 == tmp_decimal_parts); } return bret; } // truncate fragment part int ObNumber::extract_valid_int64_with_trunc(int64_t& value) const { int ret = common::OB_SUCCESS; if (!is_valid_int64(value)) { number::ObNumber tmp_number; char buf_alloc[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, ObNumber::MAX_BYTE_LEN); // need deep copy before round if (OB_FAIL(tmp_number.from(*this, allocator))) { LOG_WARN("fail to deep_copy", K(ret), K(tmp_number)); } else if (OB_FAIL(tmp_number.trunc(0))) { LOG_WARN("fail to trunc", K(ret), K(tmp_number)); } else if (!tmp_number.is_valid_int64(value)) { ret = OB_DATA_OUT_OF_RANGE; LOG_WARN("invalid const type for array index", K(tmp_number), K(ret)); } } return ret; } int ObNumber::extract_valid_uint64_with_trunc(uint64_t& value) const { int ret = common::OB_SUCCESS; if (!is_valid_uint64(value)) { number::ObNumber tmp_number; char buf_alloc[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, ObNumber::MAX_BYTE_LEN); // need deep copy before round if (OB_FAIL(tmp_number.from(*this, allocator))) { LOG_WARN("fail to deep_copy", K(ret), K(tmp_number)); } else if (OB_FAIL(tmp_number.trunc(0))) { LOG_WARN("fail to trunc", K(ret), K(tmp_number)); } else if (!tmp_number.is_valid_uint64(value)) { ret = OB_DATA_OUT_OF_RANGE; LOG_WARN("invalid const type for array index", K(tmp_number), K(ret)); } } return ret; } int ObNumber::extract_valid_int64_with_round(int64_t &value) const { int ret = common::OB_SUCCESS; if (!is_valid_int64(value)) { number::ObNumber tmp_number; char buf_alloc[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, ObNumber::MAX_BYTE_LEN); //need deep copy before round if (OB_FAIL(tmp_number.from(*this, allocator))) { LOG_WARN("fail to deep_copy", K(ret), K(tmp_number)); } else if (OB_FAIL(tmp_number.round(0))) { LOG_WARN("fail to trunc", K(ret), K(tmp_number)); } else if (!tmp_number.is_valid_int64(value)) { ret = OB_DATA_OUT_OF_RANGE; LOG_WARN("invalid const type for array index", K(tmp_number), K(ret)); } } return ret; } int ObNumber::width_bucket( const ObNumber& start, const ObNumber& end, const ObNumber& bucket, ObNumber& value, ObIAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber bucket_num, res; char buf_bucket[ObNumber::MAX_BYTE_LEN]; char buf_res[ObNumber::MAX_BYTE_LEN]; char buf_alloc1[ObNumber::MAX_BYTE_LEN]; char buf_alloc2[ObNumber::MAX_BYTE_LEN]; char buf_alloc3[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator_bucket(buf_bucket, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_res(buf_res, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator1(buf_alloc1, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator2(buf_alloc2, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator3(buf_alloc3, ObNumber::MAX_BYTE_LEN); if (OB_FAIL(bucket_num.from(bucket, allocator_bucket))) { LOG_WARN("copy bucket number failed", K(bucket_num), K(ret)); } else if (OB_FAIL(bucket_num.floor(0))) { LOG_WARN("bucket floor failed", K(bucket_num), K(ret)); } else if (OB_UNLIKELY(bucket_num.is_zero() || bucket_num.is_negative())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("bucket < 1", K(bucket_num), K(ret)); } else { ObNumber range, offset; if (start == end) { if (*this < start) { if (OB_FAIL(res.from(static_cast(0), allocator_res))) { LOG_WARN("create number 0 failed", K(res), K(ret)); } } else { ObNumber temp; if (OB_FAIL(temp.from(static_cast(1), allocator1))) { LOG_WARN("create number 1 failed", K(res), K(temp), K(ret)); } else if (OB_FAIL(bucket_num.add(temp, res, allocator_res))) { LOG_WARN("bucket add 1 failed", K(bucket_num), K(res), K(ret)); } } } else { if (start > end) { if (OB_FAIL(start.sub(end, range, allocator1))) { LOG_WARN("start sub end failed", K(start), K(end), K(range), K(ret)); } else if (OB_FAIL(start.sub(*this, offset, allocator2))) { LOG_WARN("start sub target failed", K(start), K(offset), K(ret)); } } else { if (OB_FAIL(end.sub(start, range, allocator1))) { LOG_WARN("end sub start failed", K(start), K(end), K(range), K(ret)); } else if (OB_FAIL(sub(start, offset, allocator2))) { LOG_WARN("end sub target failed", K(start), K(offset), K(ret)); } } if (OB_SUCC(ret)) { if (offset.is_negative()) { if (OB_FAIL(res.from(static_cast(0), allocator_res))) { LOG_WARN("assign 0 to res failed", K(res), K(ret)); } } else if (offset >= range) { ObNumber temp; if (OB_FAIL(temp.from(static_cast(1), allocator3))) { LOG_WARN("create number 1 failed", K(temp), K(ret)); } else if (OB_FAIL(bucket_num.add(temp, res, allocator_res))) { LOG_WARN("bucket add 1 failed", K(bucket_num), K(temp), K(res), K(ret)); } } else { ObNumber q; if (OB_FAIL(range.div(bucket_num, q, allocator3))) { LOG_WARN("width_bucket:range div bucket failed", K(range), K(bucket_num), K(q), K(ret)); } else if (OB_FAIL(offset.div(q, res, allocator_res))) { LOG_WARN("width_bucket:offset div q failed", K(offset), K(q), K(res), K(ret)); } else if (OB_FAIL(res.floor(0))) { LOG_WARN("width_bucket:value floor failed", K(res), K(ret)); } else { ObNumber temp; allocator1.free(); allocator2.free(); std::swap(allocator2, allocator_res); if (OB_FAIL(temp.from(static_cast(1), allocator1))) { LOG_WARN("create number 1 failed", K(temp), K(ret)); } else if (OB_FAIL(res.add(temp, res, allocator_res))) { LOG_WARN("value add 1 failed", K(res), K(temp), K(ret)); } } } } } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(res, allocator))) { LOG_WARN("copy res failed", K(value), K(res), K(ret)); } } } return ret; } bool ObNumber::is_valid_int() const { bool bret = false; uint64_t tmp_int_parts = 0; uint64_t tmp_decimal_parts = 0; if (OB_UNLIKELY(OB_SUCCESS != check_range(NULL, &bret, tmp_int_parts, tmp_decimal_parts))) { LOG_WARN("can't to check the param range", K(bret)); } else { bret = bret && (0 == tmp_decimal_parts); } return bret; } bool ObNumber::is_int_parts_valid_int64(int64_t& int_parts, int64_t& decimal_parts) const { bool bret = false; uint64_t tmp_int_parts = 0; uint64_t tmp_decimal_parts = 0; if (OB_UNLIKELY(OB_SUCCESS != check_range(NULL, &bret, tmp_int_parts, tmp_decimal_parts))) { LOG_WARN("can't to check the param range", K(bret)); } else { decimal_parts = tmp_decimal_parts; int_parts = is_negative() ? (-1 * tmp_int_parts) : tmp_int_parts; } LOG_DEBUG("is int parts valid int64", K(*this), K(int_parts), K(decimal_parts)); return bret; } int ObNumber::check_range( bool* is_valid_uint64, bool* is_valid_int64, uint64_t& int_parts, uint64_t& decimal_parts) const { int ret = OB_SUCCESS; if (OB_UNLIKELY((NULL == is_valid_uint64) && (NULL == is_valid_int64))) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the param is invalid", K(ret)); } else { bool* is_valid = NULL; static const int FLAG_INT64 = 0; static const int FLAG_UINT64 = 1; static const int SIGN_NEG = 0; static const int SIGN_POS = 1; int flag = FLAG_INT64; if (NULL != is_valid_uint64) { is_valid = is_valid_uint64; flag = FLAG_UINT64; } else { is_valid = is_valid_int64; } *is_valid = true; if (OB_UNLIKELY(is_zero())) { // do nothing } else { int sign = is_negative() ? SIGN_NEG : SIGN_POS; if ((SIGN_NEG == sign) && (FLAG_UINT64 == flag)) { *is_valid = false; // there are no neg guys in uint64 ! } uint64_t value = 0; static uint64_t ABS_INT64_MIN = 9223372036854775808ULL; // int64 uint64 static uint64_t THRESHOLD[2][2] = {{ABS_INT64_MIN, 0}, // neg {INT64_MAX, UINT64_MAX}}; // pos ObDigitIterator di; di.assign(d_.desc_, digits_); uint32_t digit = 0; bool from_integer = false; bool last_decimal = false; while (OB_SUCC(di.get_next_digit(digit, from_integer, last_decimal))) { if (from_integer) { // In case of overflow we can not write "value * BASE + digit <= THRESHOLD[index]" if (*is_valid && value <= (THRESHOLD[sign][flag] - digit) / BASE) { value = value * BASE + digit; } else { *is_valid = false; // no break } } else { decimal_parts = digit; break; } } ret = (OB_ITER_END == ret) ? OB_SUCCESS : ret; int_parts = value; // no matter valid or not, we set int_parts always here. } } return ret; } int ObNumber::check_precision_(const int64_t precision, const int64_t scale) { int ret = OB_SUCCESS; int64_t limit = precision - scale; ObDigitIterator di; di.assign(d_.desc_, digits_); int64_t integer_counter = 0; int64_t decimal_zero_counter = 0; uint32_t digit = 0; bool head_flag = true; bool from_integer = false; bool last_decimal = false; while (OB_SUCCESS == (ret = di.get_next_digit(digit, from_integer, last_decimal))) { if (from_integer) { if (head_flag) { integer_counter += get_digit_len(digit); } else { integer_counter += DIGIT_LEN; } if (OB_UNLIKELY(integer_counter > limit)) { _OB_LOG(WARN, "Precision=%ld scale=%ld integer_number=%ld precision overflow %s", precision, scale, integer_counter, to_cstring(*this)); ret = OB_INTEGER_PRECISION_OVERFLOW; break; } } else { if (0 != digit) { decimal_zero_counter += (DIGIT_LEN - get_digit_len(digit)); } else { decimal_zero_counter += DIGIT_LEN; } if (decimal_zero_counter >= -limit) { break; } } head_flag = false; } ret = (OB_ITER_END == ret) ? OB_SUCCESS : ret; if (OB_UNLIKELY(OB_SUCCESS == ret && decimal_zero_counter < -limit)) { LOG_WARN("precision overflow ", K(precision), K(scale), K(decimal_zero_counter), K(*this)); ret = OB_DECIMAL_PRECISION_OVERFLOW; } return ret; } int ObNumber::round_scale_(const int64_t scale, const bool using_floating_scale) { int ret = OB_SUCCESS; ObDigitIterator di; di.assign(d_.desc_, digits_); uint32_t digit = 0; bool from_integer = false; bool last_decimal = false; uint32_t integer_digits[MAX_CALC_LEN]; int64_t integer_length = 0; int64_t integer_counter = 0; uint32_t decimal_digits[MAX_CALC_LEN]; int64_t decimal_length = 0; while (OB_SUCC(di.get_next_digit(digit, from_integer, last_decimal))) { if (OB_UNLIKELY(MAX_CALC_LEN <= integer_length || MAX_CALC_LEN <= decimal_length)) { LOG_WARN("buffer size overflow", K(integer_length), K(decimal_length)); ret = OB_NUMERIC_OVERFLOW; break; } if (from_integer) { if (0 == integer_length) { integer_counter += get_digit_len(digit); } else { integer_counter += DIGIT_LEN; } integer_digits[integer_length++] = digit; } else if (0 <= scale) { if (using_floating_scale && 0 == digit && 0 == integer_length && 0 == decimal_length) { continue; } decimal_digits[decimal_length++] = digit; if ((decimal_length * DIGIT_LEN) > scale) { // LOG_DEBUG("Number need round decimal", K(decimal_length), K(scale), K(integer_counter)); break; } } else { break; } } ret = (OB_ITER_END == ret) ? OB_SUCCESS : ret; int64_t floating_scale = scale; if (OB_SUCCESS == ret && using_floating_scale) { floating_scale -= integer_counter; } // LOG_DEBUG("Number before rebuild", K(is_oracle_mode()), K(using_floating_scale), // K(scale), K(floating_scale), K(integer_counter), K(integer_length), // K(decimal_length), KPC(this), K(lbt())); if (OB_FAIL(ret)) { // do nothing } else if (0 < floating_scale) { if (OB_FAIL(round_decimal_(floating_scale, decimal_digits, decimal_length))) { LOG_ERROR("fail to get round_decimal"); } else { ret = rebuild_digits_(integer_digits, integer_length, decimal_digits, decimal_length); } } else if (0 > floating_scale) { if (OB_FAIL(round_integer_(-floating_scale, integer_digits, integer_length))) { LOG_ERROR("fail to get round_integer"); } else { ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } } else if (0 == floating_scale) { if (0 < decimal_length) { if ((5 * BASE / 10) <= decimal_digits[0]) { decimal_digits[0] = BASE; } else { decimal_digits[0] = 0; } ret = rebuild_digits_(integer_digits, integer_length, decimal_digits, 1); } else { ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } } else { /* Do nothing */ } return ret; } int ObNumber::round_scale_v2_(const int64_t scale, const bool using_floating_scale, const bool for_oracle_to_char, int16_t* res_precision /*NULL*/, int16_t* res_scale /*NULL*/) { static const uint64_t ROUND_POWS_DESC[] = { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, }; static const uint64_t ROUND_POWS_ASC[] = {1000000000, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; int ret = OB_SUCCESS; if (is_zero()) { // do nothing } else { const int64_t expr_value = get_decode_exp(d_); // xxx_length means xx digit array length const int64_t integer_length = (expr_value >= 0 ? (expr_value + 1) : 0); // e.g. 1,000000000,000000000, digits=[1], expr_value=2, len_=1, integer_length=3, valid_integer_length=1 const int64_t valid_integer_length = (d_.len_ > integer_length ? integer_length : d_.len_); // xxx_count means xx digit count const int64_t integer_count = (valid_integer_length > 0 ? (get_digit_len_v2(digits_[0]) + (integer_length - 1) * DIGIT_LEN) : 0); // len_ > integer_length means have decimal const int64_t valid_decimal_length = (d_.len_ > integer_length ? (d_.len_ - integer_length) : 0); // e.g. 0.000000000 000000001, digits=[1], expr_value=-2, len_=1, decimal_length=2, valid_decimal_length=1 const int64_t decimal_length = valid_decimal_length + ((0 == integer_length && !using_floating_scale) ? (0 - expr_value - 1) : 0); int64_t floating_scale = scale; if (is_oracle_mode()) { const int64_t decimal_prefix_zero_count = ((0 == integer_length) ? (0 - expr_value - 1 + DIGIT_LEN - get_digit_len_v2(digits_[0])) : 0); int64_t valid_precision = 0; if (for_oracle_to_char) { valid_precision = OB_MAX_NUMBER_PRECISION_INNER - 1 - (is_decimal() ? 1 : 0) - (is_negative() ? 1 : 0); } else { valid_precision = (OB_MAX_NUMBER_PRECISION_INNER - ((0 == integer_count ? decimal_prefix_zero_count : integer_count) % 2)); } int64_t r_precision = 0; int64_t r_scale = 0; int64_t decimal_non_zero_count = 0; int64_t tail_decimal_zero_count = 0; if (valid_decimal_length > 0) { remove_back_zero(digits_[d_.len_ - 1], tail_decimal_zero_count); decimal_non_zero_count = (DIGIT_LEN * valid_decimal_length - (0 == integer_length ? (DIGIT_LEN - get_digit_len_v2(digits_[0])) : 0) - tail_decimal_zero_count); } const int64_t decimal_count = decimal_length * DIGIT_LEN - tail_decimal_zero_count; if (using_floating_scale) { if (integer_count > 0) { floating_scale = valid_precision - integer_count; } else if (decimal_non_zero_count > valid_precision) { /* decimal_cnt - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_count - decimal_non_zero_count + valid_precision)); } r_precision = PRECISION_UNKNOWN_YET; r_scale = ORA_NUMBER_SCALE_UNKNOWN_YET; } else { if (integer_count > 0) { if (scale > 0) { /* 1..30th.123 scale = 30 floating_scale = 0 res_p = 30 res_s = 0 * 1..20th.123 scale = 10 floating_scale = 10 res_p = 20 * 1...42th.123 scale = 10 floating_scale = -2 res_s = 10 res_p = 40, res_s = -2 * 1.000..20th0123 scale = 22 floating_scale = 22 res_s = 22 res_p = 22*/ floating_scale = MIN(valid_precision - integer_count, scale); r_precision = MIN(valid_precision, integer_count + decimal_count); r_scale = floating_scale < 0 ? floating_scale : MIN(floating_scale, decimal_count); } else { /* 1234.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ r_precision = MIN(valid_precision, MAX(integer_count + scale, 0)); r_scale = MIN(integer_count - valid_precision, scale); } } else if (decimal_non_zero_count > valid_precision) { /* total_length - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_count - decimal_non_zero_count + valid_precision)); /* 0.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ if (scale > 0) { r_precision = MIN(valid_precision, decimal_non_zero_count - (scale - decimal_count)); } else { r_precision = 0; } r_scale = floating_scale; } } if (NULL != res_precision && NULL != res_scale) { if (using_floating_scale || (r_precision <= valid_precision && r_precision >= 0 && r_scale <= OB_MAX_NUMBER_SCALE && r_scale >= OB_MIN_NUMBER_SCALE)) { *res_precision = static_cast(r_precision); *res_scale = static_cast(r_scale); } else { LOG_WARN("got invalid precision or scale on oracle mode, use builded", K(r_precision), K(r_scale)); } } LOG_DEBUG("Number before rebuild v2", K(is_oracle_mode()), K(using_floating_scale), K(scale), K(floating_scale), K(expr_value), K(integer_length), K(valid_integer_length), K(integer_count), K(decimal_length), K(valid_decimal_length), K(decimal_count), K(decimal_prefix_zero_count), K(decimal_non_zero_count), K(r_precision), K(r_scale), KPC(this), K(lbt())); } else { if (using_floating_scale && valid_integer_length > 0) { floating_scale -= integer_count; } LOG_DEBUG("Number before rebuild v2", K(is_oracle_mode()), K(using_floating_scale), K(scale), K(floating_scale), K(expr_value), K(integer_length), K(valid_integer_length), K(decimal_length), K(valid_decimal_length), KPC(this), K(lbt())); } bool need_normalize = false; if (floating_scale > 0) { // round decimal const int64_t round_length = floating_scale / DIGIT_LEN; if (round_length >= decimal_length) { // do nothing // LOG_DEBUG("with no round", K(decimal_length), K(round_length), K(valid_decimal_length)); } else if (decimal_length > valid_decimal_length && round_length < (decimal_length - valid_decimal_length)) { // e.g. value = 0.000000000 000000000 000000001 000000002, digits=[1,2], expr_value=-3, len_=2, // decimal_length=4, valid_decimal_length=2 // round(value, 8), round(value, 9), round(value, 17) set_zero(); } else { // e.g. value = 1.000000000 000000000 000000001 000000002, digits=[1,0,0,1,2], expr_value=0, len_=5, // decimal_length=4, valid_decimal_length=4 const int64_t round = floating_scale - round_length * DIGIT_LEN; d_.len_ -= (decimal_length - (round_length + 1)); uint32_t& digit_round = *(digits_ + d_.len_ - 1); const uint64_t round_pows = ROUND_POWS_DESC[round]; const uint32_t residue = digit_round % round_pows; need_normalize = true; if (residue >= round_pows / 2) { digit_round += (round_pows - residue); } else { digit_round -= residue; } } } else if (floating_scale < 0) { floating_scale = 0 - floating_scale; const int64_t round_length = floating_scale / DIGIT_LEN; const int64_t round = floating_scale - round_length * DIGIT_LEN; int64_t round_integer_length = round_length + (0 == round ? 0 : 1); if (integer_length < round_integer_length) { set_zero(); } else if (integer_length > valid_integer_length && round_integer_length <= (integer_length - valid_integer_length)) { // e.g. 123,000000456, 000000000,000000000, // digits=[123, 456], expr_value=3, len_=2, integer_length=4, valid_integer_length=2 // round(value, -8),round(value, -18), // do nothing } else { need_normalize = true; d_.len_ = integer_length - round_integer_length + 1; uint32_t& digit_round = *(digits_ + d_.len_ - 1); const uint64_t round_pows = ROUND_POWS_ASC[round]; uint32_t residue = digit_round % round_pows; if (residue >= round_pows / 2) { digit_round += (round_pows - residue); } else { digit_round -= residue; } } } else { if (0 == decimal_length) { // do nothing } else if (valid_integer_length > 0) { need_normalize = true; d_.len_ = valid_integer_length; uint32_t& digit_round = *(digits_ + valid_integer_length); if (digit_round >= (BASE / 2)) { digits_[d_.len_ - 1] += 1; } } else { uint32_t& digit_round = *(digits_ + 0); if (digit_round >= (BASE / 2) && get_decode_exp(d_) == -1) { set_one(); } else { set_zero(); } } } if (need_normalize) { if (OB_FAIL(normalize_v2_(true, true))) { LOG_ERROR("fail to normalize_v2_", KPC(this), K(ret)); } } } LOG_DEBUG("finish round_scale_v2_", KPC(this)); return ret; } int ObNumber::round_scale_v3_(const int64_t scale, const bool using_floating_scale, const bool for_oracle_to_char, int16_t* res_precision /*NULL*/, int16_t* res_scale /*NULL*/) { static const uint64_t ROUND_POWS[] = { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1000000000, }; int ret = OB_SUCCESS; if (is_zero()) { // do nothing } else { LOG_DEBUG("before round_scale_v3_", KPC(this), K(scale), K(using_floating_scale), K(for_oracle_to_char)); const int64_t digit_0_len = get_digit_len_v2(digits_[0]); const int64_t expr_value = get_decode_exp(d_); // xxx_length means xx digit array length const int64_t integer_length = (expr_value >= 0 ? (expr_value + 1) : 0); // e.g. 1,000000000,000000000, digits=[1], expr_value=2, len_=1, integer_length=3, valid_integer_length=1 const int64_t valid_integer_length = (d_.len_ > integer_length ? integer_length : d_.len_); // xxx_count means xx digit count const int64_t integer_count = (valid_integer_length > 0 ? (digit_0_len + (integer_length - 1) * DIGIT_LEN) : 0); // len_ > integer_length means have decimal const int64_t valid_decimal_length = (d_.len_ > integer_length ? (d_.len_ - integer_length) : 0); // e.g. 0.000000000 000000001, digits=[1], expr_value=-2, len_=1, decimal_length=2, valid_decimal_length=1 const int64_t decimal_length = valid_decimal_length + ((0 == integer_length && !using_floating_scale) ? (0 - expr_value - 1) : 0); int64_t floating_scale = scale; if (is_oracle_mode()) { const int64_t decimal_prefix_zero_count = ((0 == integer_length) ? (0 - expr_value - 1 + DIGIT_LEN - digit_0_len) : 0); int64_t valid_precision = 0; if (for_oracle_to_char) { valid_precision = OB_MAX_NUMBER_PRECISION_INNER - 1 - (is_decimal() ? 1 : 0) - (is_negative() ? 1 : 0); } else { valid_precision = (OB_MAX_NUMBER_PRECISION_INNER - ((0 == integer_count ? decimal_prefix_zero_count : integer_count) % 2)); } int64_t r_precision = 0; int64_t r_scale = 0; int64_t decimal_non_zero_count = 0; int64_t tail_decimal_zero_count = 0; if (valid_decimal_length > 0) { remove_back_zero(digits_[d_.len_ - 1], tail_decimal_zero_count); decimal_non_zero_count = (DIGIT_LEN * valid_decimal_length - (0 == integer_length ? (DIGIT_LEN - digit_0_len) : 0) - tail_decimal_zero_count); } const int64_t decimal_count = decimal_length * DIGIT_LEN - tail_decimal_zero_count; if (using_floating_scale) { if (integer_count > 0) { floating_scale = valid_precision - integer_count; } else if (decimal_non_zero_count > valid_precision) { /* decimal_cnt - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_count - decimal_non_zero_count + valid_precision)); } r_precision = PRECISION_UNKNOWN_YET; r_scale = ORA_NUMBER_SCALE_UNKNOWN_YET; } else { if (integer_count > 0) { if (scale > 0) { /* 1..30th.123 scale = 30 floating_scale = 0 res_p = 30 res_s = 0 * 1..20th.123 scale = 10 floating_scale = 10 res_p = 20 * 1...42th.123 scale = 10 floating_scale = -2 res_s = 10 res_p = 40, res_s = -2 * 1.000..20th0123 scale = 22 floating_scale = 22 res_s = 22 res_p = 22*/ floating_scale = MIN(valid_precision - integer_count, scale); r_precision = MIN(valid_precision, integer_count + decimal_count); r_scale = floating_scale < 0 ? floating_scale : MIN(floating_scale, decimal_count); } else { /* 1234.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ r_precision = MIN(valid_precision, MAX(integer_count + scale, 0)); r_scale = MIN(integer_count - valid_precision, scale); } } else if (decimal_non_zero_count > valid_precision) { /* total_length - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_count - decimal_non_zero_count + valid_precision)); /* 0.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ if (scale > 0) { r_precision = MIN(valid_precision, decimal_non_zero_count - (scale - decimal_count)); } else { r_precision = 0; } r_scale = floating_scale; } } if (NULL != res_precision && NULL != res_scale) { if (OB_LIKELY(using_floating_scale || (r_precision <= valid_precision && r_precision >= 0 && r_scale <= OB_MAX_NUMBER_SCALE && r_scale >= OB_MIN_NUMBER_SCALE))) { *res_precision = static_cast(r_precision); *res_scale = static_cast(r_scale); } else { LOG_WARN("got invalid precision or scale on oracle mode, use builded", K(r_precision), K(r_scale)); } } // LOG_DEBUG("Number before rebuild v2", K(is_oracle_mode()), K(using_floating_scale), K(scale), // K(floating_scale), K(expr_value), K(integer_length), K(valid_integer_length), K(integer_count), // K(decimal_length), K(valid_decimal_length), K(decimal_count), K(decimal_prefix_zero_count), // K(decimal_non_zero_count), K(r_precision), K(r_scale), KPC(this), K(lbt())); } else { if (using_floating_scale && valid_integer_length > 0) { floating_scale -= integer_count; } // LOG_DEBUG("Number before rebuild v3", K(is_oracle_mode()), K(using_floating_scale), K(scale), // K(floating_scale), K(expr_value), K(integer_length), K(valid_integer_length), // K(decimal_length), K(valid_decimal_length), KPC(this)); } int32_t digit_id = OB_INVALID_INDEX; int32_t pow_id = OB_INVALID_INDEX; if (floating_scale > 0) { // round decimal const int64_t round_length = floating_scale / DIGIT_LEN; if (round_length >= decimal_length) { // do nothing // LOG_DEBUG("with no round", K(decimal_length), K(round_length), K(valid_decimal_length)); } else if (decimal_length > valid_decimal_length && round_length < (decimal_length - valid_decimal_length)) { // e.g. value = 0.000000000 000000000 000000001 000000002, digits=[1,2], expr_value=-3, len_=2, // decimal_length=4, valid_decimal_length=2 // round(value, 8), round(value, 9), round(value, 17) set_zero(); } else { // e.g. value = 1.000000000 000000000 000000001 000000002, digits=[1,0,0,1,2], expr_value=0, len_=5, // decimal_length=4, valid_decimal_length=4 const int64_t round = floating_scale - round_length * DIGIT_LEN; d_.len_ -= (decimal_length - (round_length + 1)); digit_id = d_.len_ - 1; pow_id = round; } } else if (floating_scale < 0) { floating_scale = 0 - floating_scale; const int64_t round_length = floating_scale / DIGIT_LEN; const int64_t round = floating_scale - round_length * DIGIT_LEN; int64_t round_integer_length = round_length + (0 == round ? 0 : 1); if (integer_length < round_integer_length) { set_zero(); } else if (integer_length > valid_integer_length && round_integer_length <= (integer_length - valid_integer_length)) { // e.g. 123,000000456, 000000000,000000000, // digits=[123, 456], expr_value=3, len_=2, integer_length=4, valid_integer_length=2 // round(value, -8),round(value, -18), // do nothing } else { d_.len_ = integer_length - round_integer_length + 1; digit_id = d_.len_ - 1; pow_id = 9 - round; } } else { if (0 == decimal_length) { // do nothing } else if (valid_integer_length > 0) { d_.len_ = valid_integer_length; digit_id = valid_integer_length; pow_id = 0; } else { uint32_t& digit_round = *(digits_ + 0); if (digit_round >= (BASE / 2) && get_decode_exp(d_) == -1) { set_one(); } else { set_zero(); } } } if (digit_id != OB_INVALID_INDEX && pow_id != OB_INVALID_INDEX) { uint32_t& digit_value = *(digits_ + digit_id); const uint64_t tmp_round_pows = ROUND_POWS[pow_id]; const uint32_t residue = digit_value % tmp_round_pows; bool need_normalize = false; if (residue >= tmp_round_pows / 2) { digit_value += (ROUND_POWS[pow_id] - residue); need_normalize = (digit_value == BASE); } else { digit_value -= residue; if (digit_value == 0) { uint32_t* tmp_digit = digits_ + d_.len_ - 1; while (tmp_digit >= digits_ && 0 == *tmp_digit) { --tmp_digit; } if (tmp_digit < digits_) { set_zero(); } else { d_.len_ = tmp_digit - digits_ + 1; } } } if (need_normalize) { --digit_id; while (digit_id >= 0) { uint32_t& tmp_digit = digits_[digit_id]; if (tmp_digit == MAX_VALUED_DIGIT) { --digit_id; } else { ++tmp_digit; break; } } if (digit_id < 0) { digits_[0] = 1; d_.len_ = 1; // check exp overflow ... ? if (NEGATIVE == d_.sign_) { --d_.exp_; } else { ++d_.exp_; } } else { d_.len_ = digit_id + 1; } } } } LOG_DEBUG("finish round_scale_v3_", KPC(this), K(scale), K(using_floating_scale), K(for_oracle_to_char)); return ret; } int ObNumber::round_precision(const int64_t precision) { static const uint64_t ROUND_POWS[] = { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1000000000, }; int ret = OB_SUCCESS; if (OB_UNLIKELY(precision < 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("precision is neg, it should not happened", KPC(this), K(precision)); } else if (is_zero()) { // do nothing } else { const int64_t digit_0_len = get_digit_len_v2(digits_[0]); const int64_t expr_value = get_decode_exp(d_); // xxx_length means xx digit array length const int64_t integer_length = (expr_value >= 0 ? (expr_value + 1) : 0); // e.g. 1,000000000,000000000, digits=[1], expr_value=2, len_=1, integer_length=3, valid_integer_length=1 const int64_t valid_integer_length = (d_.len_ > integer_length ? integer_length : d_.len_); // xxx_count means xx digit count const int64_t integer_count = (valid_integer_length > 0 ? (digit_0_len + (integer_length - 1) * DIGIT_LEN) : 0); // len_ > integer_length means have decimal const int64_t valid_decimal_length = (d_.len_ > integer_length ? (d_.len_ - integer_length) : 0); // e.g. 0.000000000 000000001, digits=[1], expr_value=-2, len_=1, decimal_length=2, valid_decimal_length=1 const int64_t decimal_length = valid_decimal_length + ((0 == integer_length) ? (0 - expr_value - 1) : 0); const int64_t decimal_prefix_zero_count = ((0 == integer_length) ? (0 - expr_value - 1 + DIGIT_LEN - digit_0_len) : 0); int64_t decimal_non_zero_count = 0; int64_t tail_decimal_zero_count = 0; if (valid_decimal_length > 0) { remove_back_zero(digits_[d_.len_ - 1], tail_decimal_zero_count); decimal_non_zero_count = (DIGIT_LEN * valid_decimal_length - (0 == integer_length ? (DIGIT_LEN - digit_0_len) : 0) - tail_decimal_zero_count); } const int64_t decimal_count = decimal_length * DIGIT_LEN - tail_decimal_zero_count; int64_t floating_scale = 0; if (integer_count > 0) { floating_scale = precision + 1 - integer_count; } else { floating_scale = (precision + 1) + (decimal_count - decimal_non_zero_count); } LOG_DEBUG("Number before round_precision", K(precision), K(floating_scale), K(expr_value), K(integer_length), K(valid_integer_length), K(integer_count), K(decimal_length), K(valid_decimal_length), K(decimal_count), K(decimal_prefix_zero_count), K(decimal_non_zero_count), KPC(this)); int32_t digit_id = OB_INVALID_INDEX; int32_t pow_id = OB_INVALID_INDEX; if (floating_scale > 0) { // round decimal const int64_t round_length = floating_scale / DIGIT_LEN; if (round_length >= decimal_length) { // do nothing // LOG_DEBUG("with no round", K(decimal_length), K(round_length), K(valid_decimal_length)); } else if (decimal_length > valid_decimal_length && round_length < (decimal_length - valid_decimal_length)) { // e.g. value = 0.000000000 000000000 000000001 000000002, digits=[1,2], expr_value=-3, len_=2, // decimal_length=4, valid_decimal_length=2 // round(value, 8), round(value, 9), round(value, 17) set_zero(); } else { // e.g. value = 1.000000000 000000000 000000001 000000002, digits=[1,0,0,1,2], expr_value=0, len_=5, // decimal_length=4, valid_decimal_length=4 const int64_t round = floating_scale - round_length * DIGIT_LEN; d_.len_ -= (decimal_length - (round_length + 1)); digit_id = d_.len_ - 1; pow_id = round; } } else if (floating_scale < 0) { floating_scale = 0 - floating_scale; const int64_t round_length = floating_scale / DIGIT_LEN; const int64_t round = floating_scale - round_length * DIGIT_LEN; int64_t round_integer_length = round_length + (0 == round ? 0 : 1); if (integer_length < round_integer_length) { set_zero(); } else if (integer_length > valid_integer_length && round_integer_length <= (integer_length - valid_integer_length)) { // e.g. 123,000000456, 000000000,000000000, // digits=[123, 456], expr_value=3, len_=2, integer_length=4, valid_integer_length=2 // round(value, -8),round(value, -18), // do nothing } else { d_.len_ = integer_length - round_integer_length + 1; digit_id = d_.len_ - 1; pow_id = 9 - round; } } else { if (0 == decimal_length) { // do nothing } else if (valid_integer_length > 0) { d_.len_ = valid_integer_length; digit_id = valid_integer_length; pow_id = 0; } else { uint32_t& digit_round = *(digits_ + 0); if (digit_round >= (BASE / 2) && get_decode_exp(d_) == -1) { set_one(); } else { set_zero(); } } } if (digit_id != OB_INVALID_INDEX && pow_id != OB_INVALID_INDEX) { uint32_t& digit_value = *(digits_ + digit_id); const uint64_t tmp_round_pows = ROUND_POWS[pow_id]; const uint32_t residue = digit_value % tmp_round_pows; bool need_normalize = false; if (residue >= tmp_round_pows / 2) { digit_value += (ROUND_POWS[pow_id] - residue); need_normalize = (digit_value == BASE); } else { digit_value -= residue; if (digit_value == 0) { uint32_t* tmp_digit = digits_ + d_.len_ - 1; while (tmp_digit >= digits_ && 0 == *tmp_digit) { --tmp_digit; } if (tmp_digit < digits_) { set_zero(); } else { d_.len_ = tmp_digit - digits_ + 1; } } } if (need_normalize) { --digit_id; while (digit_id >= 0) { uint32_t& tmp_digit = digits_[digit_id]; if (tmp_digit == MAX_VALUED_DIGIT) { --digit_id; } else { ++tmp_digit; break; } } if (digit_id < 0) { digits_[0] = 1; d_.len_ = 1; // check exp overflow ... ? if (NEGATIVE == d_.sign_) { --d_.exp_; } else { ++d_.exp_; } } else { d_.len_ = digit_id + 1; } } } } LOG_DEBUG("finish round_precision", KPC(this), K(precision)); return ret; } int ObNumber::round_scale_oracle_( const int64_t scale, const bool using_floating_scale, int16_t* res_precision, int16_t* res_scale) { int ret = OB_SUCCESS; ObDigitIterator di; di.assign(d_.desc_, digits_); uint32_t digit = 0; bool from_integer = false; bool last_decimal = false; uint32_t integer_digits[MAX_CALC_LEN]; int64_t integer_length = 0; int64_t integer_counter = 0; bool integer_is_zero = true; uint32_t decimal_digits[MAX_CALC_LEN]; int64_t decimal_length = 0; int64_t decimal_not_zero_length = 0; int64_t last_decimal_counter = 0; int64_t valid_precision = OB_MAX_NUMBER_PRECISION_INNER; int64_t r_precision = 0; int64_t r_scale = 0; int64_t decimal_prefix_zero = 0; while (OB_SUCC(di.get_next_digit(digit, from_integer, last_decimal))) { if (OB_UNLIKELY(MAX_CALC_LEN <= integer_length || MAX_CALC_LEN <= decimal_length)) { LOG_WARN("buffer size overflow", K(integer_length), K(decimal_length)); ret = OB_NUMERIC_OVERFLOW; break; } if (from_integer) { if (0 == integer_length) { integer_counter += get_digit_len(digit); } else { integer_counter += DIGIT_LEN; } if (integer_is_zero && digit != 0) { integer_is_zero = false; } integer_digits[integer_length++] = digit; } else if (0 <= scale) { if (0 == digit && 0 == integer_length && 0 == decimal_not_zero_length) { decimal_prefix_zero += DIGIT_LEN; if (using_floating_scale) { continue; } } else { if (0 == decimal_not_zero_length && !last_decimal) { decimal_prefix_zero += DIGIT_LEN - get_digit_len(digit); decimal_not_zero_length += get_digit_len(digit); } else if (last_decimal) { remove_back_zero(digit, last_decimal_counter); decimal_not_zero_length += DIGIT_LEN - last_decimal_counter; } else { decimal_not_zero_length += DIGIT_LEN; } } decimal_digits[decimal_length++] = digit; if ((decimal_length * DIGIT_LEN) > (using_floating_scale ? (scale - integer_counter) : scale)) { // LOG_DEBUG("Number need trunc decimal on oralce mode", K(decimal_length), // K(scale), K(integer_counter), K(decimal_not_zero_length), K(using_floating_scale), // K(decimal_prefix_zero)); break; } } else { break; } } ret = (OB_ITER_END == ret) ? OB_SUCCESS : ret; valid_precision -= (0 == integer_counter ? decimal_prefix_zero : integer_counter) % 2; int64_t decimal_cnt = decimal_length * DIGIT_LEN - last_decimal_counter; LOG_DEBUG("Number process on oracle mode", K(ret), K(using_floating_scale), K(scale), K(integer_counter), K(decimal_length), K(decimal_not_zero_length), K(valid_precision), K(decimal_cnt), K(last_decimal_counter)); int64_t floating_scale = scale; if (OB_SUCC(ret)) { if (using_floating_scale) { if (integer_counter > 0) { floating_scale = valid_precision - integer_counter; } else if (decimal_not_zero_length > valid_precision) { /* decimal_cnt - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_cnt - decimal_not_zero_length + valid_precision)); } r_precision = PRECISION_UNKNOWN_YET; r_scale = ORA_NUMBER_SCALE_UNKNOWN_YET; } else { if (integer_counter > 0) { if (scale > 0) { /* 1..30th.123 scale = 30 floating_scale = 0 res_p = 30 res_s = 0 * 1..20th.123 scale = 10 floating_scale = 10 res_p = 20 * 1...42th.123 scale = 10 floating_scale = -2 res_s = 10 res_p = 40, res_s = -2 * 1.000..20th0123 scale = 22 floating_scale = 22 res_s = 22 res_p = 22*/ floating_scale = MIN(valid_precision - integer_counter, scale); r_precision = MIN(valid_precision, integer_counter + decimal_cnt); r_scale = floating_scale < 0 ? floating_scale : MIN(floating_scale, decimal_cnt); } else { /* 1234.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ r_precision = MIN(valid_precision, MAX(integer_counter + scale, 0)); r_scale = MIN(integer_counter - valid_precision, scale); } } else if (decimal_not_zero_length > valid_precision) { /* total_length - non-zero decimal digit + valid decimal number */ floating_scale = MIN(scale, (decimal_cnt - decimal_not_zero_length + valid_precision)); /* 0.345 scale = -2, res_p = 2 res_s = -2 * 1234.324 scale = -10 res_p = 0 res_s = -10 * 1...42th.123 scale = -1 res_p = 40, res_s = -2*/ if (scale > 0) { r_precision = MIN(valid_precision, decimal_not_zero_length - (scale - decimal_cnt)); } else { r_precision = 0; } r_scale = floating_scale; } } if (NULL != res_precision && NULL != res_scale) { if (using_floating_scale || (r_precision <= valid_precision && r_precision >= 0 && r_scale <= OB_MAX_NUMBER_SCALE && r_scale >= OB_MIN_NUMBER_SCALE)) { *res_precision = static_cast(r_precision); *res_scale = static_cast(r_scale); } else { LOG_WARN("got invalid precision or scale on oracle mode, use builded", K(r_precision), K(r_scale)); } } // LOG_DEBUG("Number round with:", K(using_floating_scale), K(floating_scale), K(decimal_length), // K(r_precision), K(r_scale)); if (0 < floating_scale) { if (OB_FAIL(round_decimal_(floating_scale, decimal_digits, decimal_length))) { LOG_ERROR("fail to get round_decimal"); } else { ret = rebuild_digits_(integer_digits, integer_length, decimal_digits, decimal_length); } } else if (0 > floating_scale) { if (OB_FAIL(round_integer_(-floating_scale, integer_digits, integer_length))) { LOG_ERROR("fail to get round_integer"); } else { ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } } else if (0 == floating_scale) { if (0 < decimal_length) { if ((5 * BASE / 10) <= decimal_digits[0]) { decimal_digits[0] = BASE; } else { decimal_digits[0] = 0; } ret = rebuild_digits_(integer_digits, integer_length, decimal_digits, 1); } else { ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } } } return ret; } // if number=x.5 number.round_even_number() = nearest even number int ObNumber::round_even_number() { int ret = OB_SUCCESS; if (is_zero()) { // do nothing } else { const int64_t expr_value = get_decode_exp(d_); // xxx_length means xx digit array length const int64_t integer_length = (expr_value >= 0 ? (expr_value + 1) : 0); // e.g. 1,000000000,000000000, digits=[1], expr_value=2, len_=1, integer_length=3, valid_integer_length=1 const int64_t valid_integer_length = (d_.len_ > integer_length ? integer_length : d_.len_); // xxx_count means xx digit count // const int64_t integer_count = (valid_integer_length > 0 ? (get_digit_len_v2(digits_[0]) + (integer_length - 1) * // DIGIT_LEN) : 0); // len_ > integer_length means have decimal const int64_t valid_decimal_length = (d_.len_ > integer_length ? (d_.len_ - integer_length) : 0); // e.g. 0.000000000 000000001, digits=[1], expr_value=-2, len_=1, decimal_length=2, valid_decimal_length=1 const int64_t decimal_length = valid_decimal_length + ((0 == integer_length) ? (0 - expr_value - 1) : 0); bool need_normalize = false; if (0 == decimal_length) { // do nothing } else { if (valid_integer_length > 0) { need_normalize = true; d_.len_ = valid_integer_length; uint32_t& digit_round = *(digits_ + valid_integer_length); uint32_t& lowest_number_integer = *(digits_ + valid_integer_length - 1); if ((BASE / 2) < digit_round) { digits_[d_.len_ - 1] += 1; } else if ((BASE / 2) == digit_round) { if (1 < decimal_length || (1 == decimal_length && 1 == (lowest_number_integer % 2))) { digits_[d_.len_ - 1] += 1; } } } else { uint32_t& digit_round = *(digits_ + 0); if (get_decode_exp(d_) == -1 && ((digit_round > (BASE / 2)) || ((BASE / 2) == digit_round && 1 < decimal_length))) { set_one(); } else { set_zero(); } } } if (need_normalize) { if (OB_FAIL(normalize_v3_(true, true))) { LOG_ERROR("fail to normalize_v3_", KPC(this), K(ret)); } } } LOG_DEBUG("finish round_even_number_", KPC(this)); return ret; } int ObNumber::round_integer_(const int64_t scale, // >= 1 uint32_t* integer_digits, int64_t& integer_length) { static const uint64_t ROUND_POWS[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; int ret = OB_SUCCESS; if (OB_ISNULL(integer_digits) || OB_UNLIKELY(0 == DIGIT_LEN || scale < 1)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null or the DIGIT_LEN IS ZERO or the scale < 1", K(ret)); } else { int64_t round_length = scale / DIGIT_LEN; int64_t round = scale % DIGIT_LEN; LOG_DEBUG("round_integer_", K(round_length), K(round), K(integer_length)); if (integer_length < round_length) { integer_length = 0; } else { if (0 == round) { // scale >= 9, round_length >= 1 integer_length -= (round_length - 1); if ((5 * BASE / 10) <= integer_digits[integer_length - 1]) { integer_digits[integer_length - 1] = BASE; } else { integer_digits[integer_length - 1] = 0; } } else { integer_length -= round_length; uint64_t roundv = (uint64_t)integer_digits[integer_length - 1] + 5 * ROUND_POWS[round] / 10; roundv /= ROUND_POWS[round]; roundv *= ROUND_POWS[round]; integer_digits[integer_length - 1] = (uint32_t)roundv; } } } return ret; } int ObNumber::round_decimal_(const int64_t scale, // >= 1 uint32_t* decimal_digits, int64_t& decimal_length) { static const uint64_t ROUND_POWS[] = {0, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10}; int ret = OB_SUCCESS; if (OB_ISNULL(decimal_digits) || OB_UNLIKELY(0 == DIGIT_LEN || scale < 1)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null or the DIGIT_LEN IS ZERO or the scale < 1", K(ret)); } else { int64_t round_length = scale / DIGIT_LEN; int64_t round = scale % DIGIT_LEN; if (decimal_length <= round_length) { // do nothing LOG_DEBUG("with no round", K(decimal_length), K(round_length)); } else { decimal_length = std::min(decimal_length, round_length + 1); if (0 == round) { // scale >= 9, decimal_length >= 2 if ((5 * BASE / 10) <= decimal_digits[decimal_length - 1]) { decimal_digits[decimal_length - 1] = BASE; } else { decimal_digits[decimal_length - 1] = 0; } } else { uint64_t roundv = (uint64_t)decimal_digits[decimal_length - 1] + 5 * ROUND_POWS[round] / 10; roundv /= ROUND_POWS[round]; roundv *= ROUND_POWS[round]; decimal_digits[decimal_length - 1] = (uint32_t)roundv; } } } return ret; } int ObNumber::trunc_scale_(int64_t scale, bool using_floating_scale) { int ret = OB_SUCCESS; ObDigitIterator di; di.assign(d_.desc_, digits_); uint32_t digit = 0; bool from_integer = false; bool last_decimal = false; uint32_t integer_digits[MAX_CALC_LEN]; int64_t integer_length = 0; int64_t integer_counter = 0; uint32_t decimal_digits[MAX_CALC_LEN]; int64_t decimal_length = 0; while (OB_SUCC(di.get_next_digit(digit, from_integer, last_decimal))) { if (OB_UNLIKELY(MAX_CALC_LEN <= integer_length || MAX_CALC_LEN <= decimal_length)) { LOG_WARN("buffer size overflow", K(integer_length), K(decimal_length)); ret = OB_NUMERIC_OVERFLOW; break; } if (from_integer) { if (0 == integer_length) { integer_counter += get_digit_len(digit); } else { integer_counter += DIGIT_LEN; } integer_digits[integer_length++] = digit; } else if (0 <= scale) { if (using_floating_scale && 0 == digit && 0 == integer_length && 0 == decimal_length) { continue; } decimal_digits[decimal_length++] = digit; if ((decimal_length * DIGIT_LEN) > scale) { break; } } else { break; } } ret = (OB_ITER_END == ret) ? OB_SUCCESS : ret; int64_t floating_scale = scale; if (OB_SUCCESS == ret && using_floating_scale) { floating_scale -= integer_counter; } if (OB_FAIL(ret)) { // do nothing } else if (0 < floating_scale) { if (OB_FAIL(trunc_decimal_(floating_scale, decimal_digits, decimal_length))) { LOG_ERROR("fail to get trunc decimal", K(ret)); } else { ret = rebuild_digits_(integer_digits, integer_length, decimal_digits, decimal_length); } } else if (0 > floating_scale) { // todo if (OB_FAIL(trunc_integer_(-floating_scale, integer_digits, integer_length))) { LOG_ERROR("fail to get trunc integer", K(ret)); } else { ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } } else if (0 == floating_scale) { // todo ret = rebuild_digits_(integer_digits, integer_length, NULL, 0); } else { /* Do nothing */ } return ret; } int ObNumber::trunc_integer_(const int64_t scale, uint32_t* integer_digits, int64_t& integer_length) { int ret = OB_SUCCESS; static const uint64_t TRUNC_POWS[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; if (OB_UNLIKELY(0 == DIGIT_LEN || scale <= 0)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(ERROR, "DIGIT_LEN is zero or scale is not positive", K(ret), K(scale)); } else if (integer_length > 0) { // tips: in terms of "3333123456789555555555.123" // integer_length = 3 and integer_digits[0]=3333, integer_digits[1] = 123456789 integer_digits[2] = 555555555 int64_t trunc_length = (scale - 1) / DIGIT_LEN + 1; int64_t trunc = scale % DIGIT_LEN; if (integer_length < trunc_length) { integer_length = 0; } else { if (0 == trunc) { // such as "3333123456789555555555.123" and scale = 9 integer_length -= trunc_length; } else { // such as "3333123456789555555555.123" and scale = 3, change 555555555 to 555555000 // integer_length >= trunc_length and trunc_length > 0 , so it holds that // integer_length - trunc_length + 1 - 1 = integer_length - trunc_length >= 0 and // integer_length - trunc_length + 1 - 1 = integer_length - trunc_length < integer_length // we need to check the bound here and can use integer_digits[integer_length - 1] safety integer_length -= (trunc_length - 1); uint64 truncdv = static_cast(integer_digits[integer_length - 1]); truncdv /= TRUNC_POWS[trunc]; truncdv *= TRUNC_POWS[trunc]; integer_digits[integer_length - 1] = static_cast(truncdv); } } } return ret; } int ObNumber::trunc_decimal_(const int64_t scale, uint32_t* decimal_digits, int64_t& decimal_length) { int ret = OB_SUCCESS; static const uint64_t TRUNC_POWS[] = {0, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10}; if (OB_UNLIKELY(0 == DIGIT_LEN || scale <= 0)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the DIGIT_LEN is zero or scale is not positive", K(ret), K(scale)); } else if (decimal_length > 0) { int64_t trunc_length = (scale - 1) / DIGIT_LEN + 1; int64_t trunc = scale % DIGIT_LEN; if (decimal_length < trunc_length) { // do nothing } else { decimal_length = trunc_length; if (0 == trunc) { // such as : "1.123456789123456789" when scale = 9 trunc will be 0 // decimal_length will be changed from 2 to 1 (trunc_length). // and, we do nothing here. } else { uint64 truncdv = static_cast(decimal_digits[decimal_length - 1]); truncdv /= TRUNC_POWS[trunc]; truncdv *= TRUNC_POWS[trunc]; decimal_digits[decimal_length - 1] = static_cast(truncdv); } } } return ret; } // handle decoded digits without tail flag int ObNumber::normalize_(uint32_t* digits, const int64_t length) { int ret = OB_SUCCESS; if (OB_ISNULL(digits)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(ret)); } else { int64_t tmp_length = length; int64_t start = 0; for (int64_t i = 0; i < tmp_length; ++i) { if (0 != digits[i]) { break; } ++start; } uint32_t carry = 0; for (int64_t i = tmp_length - 1; i >= start; --i) { digits[i] += carry; if (BASE <= digits[i]) { digits[i] -= (uint32_t)BASE; carry = 1; } else { carry = 0; } } // carry may generate extra zero, so reduce zero on tail, must after handle carry int64_t end = tmp_length - 1; for (int64_t i = tmp_length - 1; i >= start; --i) { if (0 != digits[i] && BASE != digits[i]) { break; } --end; } tmp_length = end - start + 1; tmp_length = (0 < tmp_length) ? tmp_length : 0; if (0 < carry) { if (OB_UNLIKELY(0 != tmp_length)) { LOG_WARN("unexpected length", K(tmp_length)); ret = OB_ERR_UNEXPECTED; } else { digits_[0] = carry; d_.len_ = 1; if (NEGATIVE == d_.sign_) { --d_.exp_; } else { ++d_.exp_; } } } else { if (digits_ != &digits[start]) { memmove(digits_, &digits[start], tmp_length * ITEM_SIZE(digits_)); } d_.len_ = (uint8_t)tmp_length; if (0 == d_.len_) { set_zero(); } } } return ret; } // handle decoded digits without tail flag int ObNumber::normalize_v2_(const bool from_calc /*true*/, const bool only_normalize_tailer /*false*/) { int ret = OB_SUCCESS; if (OB_ISNULL(digits_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(ret)); } else { int64_t tmp_length = d_.len_; int64_t start = 0; if (!only_normalize_tailer) { for (int64_t i = 0; i < tmp_length; ++i) { if (0 != digits_[i]) { break; } ++start; } } uint32_t carry = 0; int64_t end = tmp_length - 1; if (from_calc) { for (int64_t i = tmp_length - 1; i >= start; --i) { digits_[i] += carry; if (digits_[i] >= BASE) { digits_[i] -= (uint32_t)BASE; carry = 1; } else { carry = 0; } } // carry may generate extra zero, so reduce zero on tail, must after handle carry for (int64_t i = tmp_length - 1; i >= start; --i) { if (0 != digits_[i]) { break; } --end; } } tmp_length = end - start + 1; if (tmp_length < 0) { tmp_length = 0; } if (0 < carry) { if (OB_UNLIKELY(0 != tmp_length)) { LOG_WARN("unexpected length", K(tmp_length)); ret = OB_ERR_UNEXPECTED; } else { digits_[0] = carry; d_.len_ = 1; if (NEGATIVE == d_.sign_) { --d_.exp_; } else { ++d_.exp_; } } } else { if (digits_ != digits_ + start) { memmove(digits_, digits_ + start, tmp_length * ITEM_SIZE(digits_)); } d_.len_ = (uint8_t)tmp_length; if (0 == d_.len_) { set_zero(); } } } return ret; } // handle decoded digits without tail flag int ObNumber::normalize_v3_(const bool from_calc /*true*/, const bool only_normalize_tailer /*false*/) { int ret = OB_SUCCESS; if (OB_ISNULL(digits_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(ret)); } else { int64_t tmp_length = d_.len_; int64_t start = 0; if (!only_normalize_tailer) { for (int64_t i = 0; i < tmp_length && 0 == digits_[i]; ++i) { ++start; } } uint32_t carry = 0; int64_t end = tmp_length - 1; if (from_calc) { for (int64_t i = end; i >= start; --i) { uint32_t& tmp_digit = digits_[i]; tmp_digit += carry; if (BASE == tmp_digit) { tmp_digit = 0; --end; carry = 1; } else if (0 == tmp_digit) { --end; carry = 0; } else { carry = 0; break; } } } tmp_length = end - start + 1; if (tmp_length < 0) { tmp_length = 0; } if (carry > 0) { if (OB_UNLIKELY(0 != tmp_length)) { LOG_WARN("unexpected length", K(tmp_length)); ret = OB_ERR_UNEXPECTED; } else { digits_[0] = carry; d_.len_ = 1; if (NEGATIVE == d_.sign_) { --d_.exp_; } else { ++d_.exp_; } } } else { if (0 == tmp_length) { set_zero(); } else { if (digits_ != digits_ + start) { memmove(digits_, digits_ + start, tmp_length * ITEM_SIZE(digits_)); } d_.len_ = (uint8_t)tmp_length; } } } return ret; } int ObNumber::rebuild_digits_(const uint32_t* integer_digits, const int64_t integer_length, const uint32_t* decimal_digits, const int64_t decimal_length) { int ret = OB_SUCCESS; uint32_t digits[MAX_CALC_LEN] = {}; int64_t length = 0; if (NULL != integer_digits && 0 < integer_length) { if (OB_UNLIKELY(MAX_CALC_LEN <= (length + integer_length))) { _OB_LOG( WARN, "buffer size overflow, cap=%ld length=%ld integer_length=%ld", MAX_CALC_LEN, length, integer_length); ret = OB_NUMERIC_OVERFLOW; } else { MEMCPY(digits, integer_digits, integer_length * ITEM_SIZE(digits_)); length = integer_length; } } if (OB_SUCCESS == ret && NULL != decimal_digits && 0 < decimal_length) { if (OB_UNLIKELY(MAX_CALC_LEN <= (length + decimal_length))) { _OB_LOG( WARN, "buffer size overflow, cap=%ld length=%ld decimal_length=%ld", MAX_CALC_LEN, length, decimal_length); ret = OB_NUMERIC_OVERFLOW; } else { MEMCPY(&digits[length], decimal_digits, decimal_length * ITEM_SIZE(digits)); length += decimal_length; } } if (OB_SUCC(ret)) { ret = normalize_(digits, length); } OB_LOG(DEBUG, "succ to rebuild_digits_", K(integer_length), K(decimal_length), K(length), KPC(this)); return ret; } const char* ObNumber::format() const { // TODO: To Be Removed. Use stack local instead. static const int64_t BUFFER_NUM = 64; static const int64_t BUFFER_SIZE = MAX_PRINTABLE_SIZE; static __thread char buffers[BUFFER_NUM][BUFFER_SIZE]; static __thread uint64_t i = 0; char* buffer = buffers[i++ % BUFFER_NUM]; int64_t length = 0; if (OB_UNLIKELY(OB_SUCCESS != format(buffer, BUFFER_SIZE, length, -1))) { LOG_ERROR("fail to format buffer"); } else { buffer[length] = '\0'; } return buffer; } int ObNumber::format_v1(char* buf, const int64_t buf_len, int64_t& pos, int16_t scale) const { int ret = OB_SUCCESS; uint32_t digits[MAX_STORE_LEN] = {0}; bool prev_from_integer = true; int64_t pad_zero_count = scale; if (is_oracle_mode()) { pad_zero_count = 0; } ObNumber buf_nmb; const ObNumber* nmb = this; if (scale >= 0) { if (OB_FAIL(buf_nmb.from_(*this, digits, MAX_STORE_LEN))) { } else if (OB_FAIL(buf_nmb.round(scale))) { } else { nmb = &buf_nmb; } } if (OB_SUCC(ret) && 0 == nmb->d_.len_) { ret = databuff_printf(buf, buf_len, pos, "0"); } else { if (OB_SUCC(ret)) { if (nmb->is_negative()) { ret = databuff_printf(buf, buf_len, pos, "-"); } // No additional 0 in oracle mode. E.G: 0.2345 => .2345, -0.2345 => -.2345. if (OB_SUCCESS == ret && nmb->is_decimal() && !is_oracle_mode()) { ret = databuff_printf(buf, buf_len, pos, "0"); } if (OB_SUCC(ret)) { ObDigitIterator di; di.assign(nmb->get_desc_value(), nmb->get_digits()); uint32_t digit = 0; bool head_flag = true; bool from_integer = false; bool last_decimal = false; int tmp_ret = OB_SUCCESS; // used for iteration of get_next_digit while (OB_SUCCESS == ret && OB_SUCCESS == (tmp_ret = di.get_next_digit(digit, from_integer, last_decimal))) { if (prev_from_integer && !from_integer) { // dot ret = databuff_printf(buf, buf_len, pos, "."); } if (OB_SUCC(ret)) { if (!from_integer && !last_decimal) { pad_zero_count -= DIGIT_LEN; } if (head_flag && from_integer) { // first integer ret = databuff_printf(buf, buf_len, pos, "%u", digit); } else if (last_decimal) { // last decimal int64_t counter = 0; uint32_t tmp = remove_back_zero(digit, counter); ret = databuff_printf(buf, buf_len, pos, ObNumber::BACK_DIGIT_FORMAT[counter], tmp); pad_zero_count -= (DIGIT_LEN - counter); } else { // normal digit ret = databuff_printf(buf, buf_len, pos, DIGIT_FORMAT, digit); } } if (OB_SUCC(ret)) { prev_from_integer = from_integer; head_flag = false; } } // end while. end iteration if (OB_SUCC(ret)) { ret = (OB_ITER_END == tmp_ret) ? OB_SUCCESS : tmp_ret; } } } } // pad zero. if (OB_SUCCESS == ret && pad_zero_count > 0) { if (prev_from_integer) { ret = databuff_printf(buf, buf_len, pos, "."); } if (OB_SUCC(ret)) { if (OB_UNLIKELY(pad_zero_count > FLOATING_SCALE)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the param is invalid", K(ret), K(pad_zero_count)); } else { char zeros[FLOATING_SCALE + 1] = "000000000000000000000000000000000000000000000000000000000000000000000000"; zeros[pad_zero_count] = 0; ret = databuff_printf(buf, buf_len, pos, "%s", zeros); } } } return ret; } int ObNumber::format_int64(char* buf, int64_t& pos, const int16_t scale, bool& is_finish) const { int ret = OB_SUCCESS; is_finish = true; const int64_t orig_pos = pos; if (is_zero()) { buf[pos++] = '0'; } else { if (is_negative()) { buf[pos++] = '-'; } const int32_t expr_value = get_decode_exp(d_); if (!is_integer(expr_value)) { is_finish = false; } else if (is_int32(expr_value)) { const int64_t format_length = ObFastFormatInt::format_unsigned(digits_[0], buf + pos); if (OB_UNLIKELY(format_length > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "digit", digits_[0], KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { pos += format_length; } } else if (is_int64_without_expr(expr_value)) { const int64_t format_length = ObFastFormatInt::format_unsigned(digits_[0], buf + pos); if (OB_UNLIKELY(format_length > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "digit", digits_[0], KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { pos += format_length; ObFastFormatInt ffi(digits_[1]); if (OB_UNLIKELY(ffi.length() > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "digit", digits_[1], KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { MEMSET(buf + pos, '0', DIGIT_LEN - ffi.length()); MEMCPY(buf + pos + DIGIT_LEN - ffi.length(), ffi.ptr(), ffi.length()); pos += DIGIT_LEN; } } } else if (is_int64_with_expr(expr_value)) { const int64_t format_length = ObFastFormatInt::format_unsigned(digits_[0], buf + pos); if (OB_UNLIKELY(format_length > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "digit", digits_[0], KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { pos += format_length; MEMSET(buf + pos, '0', DIGIT_LEN); pos += DIGIT_LEN; } } else { is_finish = false; } } if (OB_SUCC(ret) && is_finish) { // pad zero. if (!is_oracle_mode() && scale > 0) { buf[pos++] = '.'; if (OB_UNLIKELY(scale > FLOATING_SCALE)) { is_finish = false; pos = orig_pos; ret = OB_ERR_UNEXPECTED; LOG_WARN("scale is to large", K(scale), K(ret)); } else { MEMCPY(buf + pos, FLOATING_ZEROS, scale); pos += scale; buf[pos] = '\0'; } } else { buf[pos] = '\0'; } ObString tmp_str(pos - orig_pos, buf); LOG_DEBUG("finish format int64", KPC(this), K(scale), K(is_oracle_mode()), K(tmp_str)); } else { pos = orig_pos; } return ret; } int ObNumber::format_v2(char* buf, const int64_t buf_len, int64_t& pos, int16_t scale) const { int ret = OB_SUCCESS; bool is_finish = false; const int64_t orig_pos = pos; const int64_t max_need_size = get_max_format_length() + ((!is_oracle_mode() && scale > 0) ? scale : 0); if (OB_ISNULL(buf) || OB_UNLIKELY((buf_len - pos) < 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("argument is invalid", KP(buf), K(buf_len), K(pos), K(ret)); } else if (OB_UNLIKELY((buf_len - pos) < max_need_size)) { ret = OB_SIZE_OVERFLOW; LOG_TRACE("size is overflow", K(buf_len), K(pos), K(max_need_size), KPC(this), K(scale), K(ret)); } else if (OB_FAIL(format_int64(buf, pos, scale, is_finish))) { LOG_ERROR("format_int64 failed", KPC(this), K(ret)); } else if (is_finish) { // fast path succ } else { pos = orig_pos; bool prev_from_integer = true; int64_t pad_zero_count = (is_oracle_mode() ? 0 : scale); ObNumber buf_nmb; uint32_t digits[MAX_STORE_LEN] = {0}; const ObNumber* nmb = this; if (!is_integer(get_decode_exp(d_)) && scale >= 0) { if (OB_FAIL(buf_nmb.from_(*this, digits, MAX_STORE_LEN))) { } else if (OB_FAIL(buf_nmb.round(scale))) { } else if (OB_UNLIKELY(buf_len - pos < buf_nmb.get_max_format_length())) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size is overflow", "buf_size", buf_len - pos, "max_need_size", buf_nmb.get_max_format_length(), K(scale), K(buf_nmb), K(ret)); } else { nmb = &buf_nmb; } } if (OB_FAIL(ret)) { } else if (nmb->is_zero()) { buf[pos++] = '0'; } else { if (is_negative()) { buf[pos++] = '-'; } // No additional 0 in oracle mode. E.G: 0.2345 => .2345, -0.2345 => -.2345. if (nmb->is_decimal() && !is_oracle_mode()) { buf[pos++] = '0'; } ObDigitIterator di; di.assign(nmb->get_desc_value(), nmb->get_digits()); uint32_t digit = 0; ObDigitIterator::NextDigitEnum nd_enum = ObDigitIterator::NextDigitEnum::ND_END; while (OB_SUCC(ret) && ObDigitIterator::NextDigitEnum::ND_END != (nd_enum = di.get_next_digit(digit))) { switch (nd_enum) { case ObDigitIterator::NextDigitEnum::ND_HEAD_INTEGER: { const int64_t format_length = ObFastFormatInt::format_unsigned(digit, buf + pos); if (OB_UNLIKELY(format_length > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "digit", digit, KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { pos += format_length; } break; } case ObDigitIterator::NextDigitEnum::ND_BODY_DECIMAL: if (prev_from_integer) { // dot buf[pos++] = '.'; prev_from_integer = false; } pad_zero_count -= DIGIT_LEN; case ObDigitIterator::NextDigitEnum::ND_BODY_INTEGER: { // normal digit ObFastFormatInt ffi(digit); if (OB_UNLIKELY(ffi.length() > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "ffi", ffi.str(), K(digit), KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { MEMSET(buf + pos, '0', DIGIT_LEN - ffi.length()); MEMCPY(buf + pos + DIGIT_LEN - ffi.length(), ffi.ptr(), ffi.length()); pos += DIGIT_LEN; } break; } case ObDigitIterator::NextDigitEnum::ND_TAIL_DECIMAL: { // last decimal if (prev_from_integer) { // dot buf[pos++] = '.'; prev_from_integer = false; } ObFastFormatInt ffi(digit); if (OB_UNLIKELY(ffi.length() > DIGIT_LEN)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("digits is unexpected", "ffi", ffi.str(), K(digit), KPC(this), K(ret)); // print number will not report error ret, we need make use find it MEMCPY(buf + pos, NUMBER_ERRMSG.ptr(), NUMBER_ERRMSG.length()); } else { const int64_t tail_zero_count = ffi.get_tail_zero_count(); MEMSET(buf + pos, '0', DIGIT_LEN - ffi.length()); MEMCPY(buf + pos + DIGIT_LEN - ffi.length(), ffi.ptr(), ffi.length() - tail_zero_count); pos += (DIGIT_LEN - tail_zero_count); pad_zero_count -= (DIGIT_LEN - tail_zero_count); } break; } default: { LOG_ERROR("it should not arrive here", K(nd_enum)); } } } // end while. end iteration } // pad zero. if (OB_SUCC(ret) && pad_zero_count > 0) { if (prev_from_integer) { buf[pos++] = '.'; } if (OB_UNLIKELY(pad_zero_count > FLOATING_SCALE)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the param is invalid", K(ret), K(pad_zero_count)); } else if (OB_UNLIKELY(pos + pad_zero_count > buf_len)) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size is overflow", K(pos), K(pad_zero_count), K(buf_len), K(ret)); } else { MEMCPY(buf + pos, FLOATING_ZEROS, pad_zero_count); pos += pad_zero_count; } } if (OB_SUCC(ret)) { buf[pos] = '\0'; } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(pos >= buf_len)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("size is overflow, it should not happened", K(pos), K(buf_len), KPC(this), K(scale), K(ret)); OB_ASSERT(pos < buf_len); } else if (OB_UNLIKELY(pos - orig_pos > max_need_size)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("calc size is too litter", "write_len", pos - orig_pos, K(max_need_size), K(buf_len), KPC(this), K(scale), K(ret)); OB_ASSERT(pos - orig_pos <= max_need_size); } } return ret; } // oracle max store 20 bytes number(39~40 number). when using to_char, only store 40 number at most int ObNumber::format_with_oracle_limit(char* buf, const int64_t buf_len, int64_t& pos, int16_t scale) const { int ret = common::OB_SUCCESS; number::ObNumber tmp_number; char buf_alloc[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, ObNumber::MAX_BYTE_LEN); // need deep copy before round if (OB_FAIL(tmp_number.from(*this, allocator))) { LOG_WARN("fail to deep_copy", K(ret), K(tmp_number)); } else if (OB_FAIL(tmp_number.round(ObNumber::MAX_SCALE, true))) { LOG_WARN("fail to round", K(ret), K(tmp_number)); } else if (OB_FAIL(tmp_number.format(buf, buf_len, pos, scale))) { LOG_WARN("fail to format", K(ret), K(tmp_number)); } return ret; } int ObNumber::get_npi_(double n, ObNumber& out, ObIAllocator& alloc, const bool do_rounding) const { int ret = OB_SUCCESS; // remember to change this const int64_t LOCAL_ALLOC_TIMES = 1; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); const int64_t MAX_DOUBLE_PRINT_SIZE = 512; char buf[MAX_DOUBLE_PRINT_SIZE] = {0}; int64_t double_print_len = ob_gcvt_opt(n, OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL, lib::is_oracle_mode()); ObNumber n_obnum; ObNumber pi = get_pi(); size_t str_len = strlen(buf); if (0 >= str_len) { ret = OB_ERR_UNEXPECTED; LOG_WARN("len of number string should not less than zero", K(ret), K(str_len)); } else if (OB_FAIL(n_obnum.from_sci_opt(buf, str_len, local_alloc, NULL, NULL, do_rounding))) { LOG_WARN("n_obnum.from(n) failed", K(n), K(ret)); } else if (OB_FAIL(pi.mul_v3(n_obnum, out, alloc, true, do_rounding))) { LOG_WARN("pi.mul(n_obnum) failed", K(n_obnum), K(pi), K(out)); } return ret; } int ObNumber::get_npi_(int64_t n, ObNumber& out, ObIAllocator& alloc, const bool do_rounding) const { int ret = OB_SUCCESS; // remember to change this const int64_t LOCAL_ALLOC_TIMES = 1; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); ObNumber n_obnum; ObNumber pi = get_pi(); if (OB_FAIL(n_obnum.from(n, local_alloc))) { LOG_WARN("n_obnum.from(n) failed", K(n), K(ret)); } else if (OB_FAIL(pi.mul_v3(n_obnum, out, alloc, true, do_rounding))) { LOG_WARN("pi.mul(n_obnum) failed", K(n_obnum), K(pi), K(out)); } else { // done } return ret; } int ObNumber::simple_factorial_for_sincos_(int64_t start, ObIAllocator& allocator, ObNumber& result) const { int ret = OB_SUCCESS; ObNumber y; result.set_one(); // remember to change this const int64_t LOCAL_ALLOC_TIMES = 3; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); if (OB_FAIL(y.from(start, local_alloc))) { LOG_WARN("y.from(start) failed", K(y), K(start), K(ret)); } else if (OB_FAIL(result.mul_v3(y, result, local_alloc, true, false))) { LOG_WARN("result.mul_v3(y) failed", K(result), K(y), K(ret)); } else if (OB_FAIL(y.add_v3(ObNumber::get_positive_one(), y, local_alloc, true, false))) { LOG_WARN("y.add(1) failed", K(y), K(ret)); } else if (OB_FAIL(result.mul_v3(y, result, allocator, true, false))) { LOG_WARN("result.mul(y) failed", K(result), K(y), K(ret)); } else { // done LOG_DEBUG("factorial done", K(result)); } return ret; } int ObNumber::taylor_series_sin_(const ObNumber& transformed_x, ObNumber& out, ObIAllocator& allocator, const ObNumber& range_low, const ObNumber& range_high) const { int ret = OB_SUCCESS; if (!(range_low <= transformed_x && transformed_x <= range_high)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("transform x before do taylor series expansion", K(transformed_x)); } else { // remember to change this const int64_t LOCAL_ALLOC_TIMES = 5; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); ObNumber iter_result; ObNumber divisor; ObNumber square_x; ObNumber tmp_out; if (OB_FAIL(iter_result.from(transformed_x, local_alloc))) { LOG_WARN("iter_result.from(transformed_x) failed", K(iter_result), K(transformed_x), K(ret)); } else if (OB_FAIL(square_x.from(transformed_x, local_alloc))) { LOG_WARN("square_x.from(transformed_x) failed", K(square_x), K(transformed_x), K(ret)); } else if (OB_FAIL(square_x.mul_v3(transformed_x, square_x, local_alloc, true, false))) { LOG_WARN("square_x.mul(transformed_x) failed", K(square_x), K(transformed_x), K(ret)); } else if (OB_FAIL(tmp_out.from(transformed_x, local_alloc))) { LOG_WARN("tmp_out.from(transformed_x) failed", K(tmp_out), K(transformed_x), K(ret)); } else if (OB_FAIL(divisor.from(ObNumber::get_positive_one(), local_alloc))) { LOG_WARN("divisor.from(1) failed", K(divisor), K(ret)); } else { size_t idx = 1; size_t start_div_num = 2; const int64_t LOCAL_ALLOC_TIMES_FOR_LOOP = 4; const int64_t LOCAL_BUF_SIZE_FOR_LOOP = LOCAL_ALLOC_TIMES_FOR_LOOP * MAX_CALC_BYTE_LEN; char local_buf_for_loop_1[LOCAL_BUF_SIZE_FOR_LOOP]; char local_buf_for_loop_2[LOCAL_BUF_SIZE_FOR_LOOP]; ObDataBuffer local_alloc_for_loop_1(local_buf_for_loop_1, LOCAL_BUF_SIZE_FOR_LOOP); ObDataBuffer local_alloc_for_loop_2(local_buf_for_loop_2, LOCAL_BUF_SIZE_FOR_LOOP); LOG_DEBUG("start to calc taylor series expansion for sin", K(iter_result), K(tmp_out), K(square_x), K(divisor)); while (OB_SUCC(ret) && (false == iter_result.is_zero())) { if (OB_FAIL(iter_result.mul_v3(square_x, iter_result, local_alloc_for_loop_1, true, false))) { LOG_WARN("iter_result.mul_v3(square_x) failed", K(ret), K(iter_result), K(square_x)); } else if (OB_FAIL(simple_factorial_for_sincos_(start_div_num, local_alloc_for_loop_1, divisor))) { LOG_WARN("simple_factorial_for_sincos_(start_div_num) failed", K(ret)); } else if (OB_FAIL(iter_result.div_v3( divisor, iter_result, local_alloc_for_loop_1, ObNumber::OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("iter_result.div_v3(divisor) failed", K(ret), K(iter_result)); } else { if (idx & 1) { // odd if (OB_FAIL(tmp_out.sub_v3(iter_result, tmp_out, local_alloc_for_loop_1, true, false))) { LOG_WARN("tmp_out.sub_v3(iter_result) failed", K(ret), K(tmp_out)); } } else { if (OB_FAIL(tmp_out.add_v3(iter_result, tmp_out, local_alloc_for_loop_1, true, false))) { LOG_WARN("tmp_out.add_v3(iter_result) failed", K(ret), K(tmp_out)); } } LOG_DEBUG("iteration computing", K(iter_result), K(tmp_out)); local_alloc_for_loop_2.free(); std::swap(local_alloc_for_loop_1, local_alloc_for_loop_2); idx += 1; start_div_num += 2; } } LOG_DEBUG("iteration done", K(tmp_out)); if (OB_SUCC(ret)) { if (OB_FAIL(out.from(tmp_out, allocator))) { LOG_WARN("out.from(tmp_out) failed", K(out), K(tmp_out)); } } } } return ret; } int ObNumber::sin(ObNumber& out, ObIAllocator& allocator, const bool do_rounding) const { int ret = OB_SUCCESS; bool neg = false; ; ObNumber pi; ObNumber range_low; // 0 ObNumber range_high; // 2pi ObNumber tmp_out; ObNumber transformed_x; // between [0, pi] ObNumber x = *this; // remember to change this const int64_t LOCAL_ALLOC_TIMES = 7; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); if (x.is_zero()) { if (OB_FAIL(out.from(static_cast(0), allocator))) { LOG_WARN("out.from(0) failed", K(ret), K(out)); } } else if (OB_FAIL(get_npi_(static_cast(2), range_high, local_alloc, false))) { LOG_WARN("get_npi_(2) failed", K(ret)); } else if (OB_FAIL(get_npi_(static_cast(1), pi, local_alloc, false))) { LOG_WARN("get_npi_(1) failed", K(ret)); } else { range_low.set_zero(); if (x.is_negative()) { neg = !neg; if (OB_FAIL(x.negate(x, local_alloc))) { LOG_WARN("x.negate() failed", K(x), K(ret)); } } if (OB_SUCC(ret)) { if (!(range_low <= x && x <= range_high)) { if (OB_FAIL(x.rem(range_high, transformed_x, local_alloc))) { LOG_WARN("x.rem(range_high) failed", K(ret), K(x), K(range_high)); } } else { if (OB_FAIL(transformed_x.from(x, local_alloc))) { LOG_WARN("transformed_x.from(x) failed", K(x), K(ret)); } } } if (OB_SUCC(ret)) { // transformed_x now in [0, 2pi] // make it in [0, pi] if (pi < transformed_x) { neg = !neg; if (OB_FAIL(transformed_x.sub_v3(pi, transformed_x, local_alloc, true, false))) { LOG_WARN("transformed_x.sub_v3(pi) failed", K(transformed_x), K(pi)); } } } LOG_DEBUG("transform input done, start to taylor series expansion", K(neg), K(transformed_x), K(x)); if (OB_SUCC(ret)) { if (OB_FAIL(taylor_series_sin_(transformed_x, tmp_out, local_alloc, range_low, pi))) { LOG_WARN("taylor_series_sin_(transformed_x) failed", K(ret), K(transformed_x)); } else { if (neg) { if (OB_FAIL(tmp_out.negate(tmp_out, local_alloc))) { LOG_WARN("tmp_out.negate() failed", K(ret), K(tmp_out)); } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(tmp_out.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(tmp_out)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(out.from(tmp_out, allocator))) { LOG_WARN("out.from(tmp_out) failed", K(ret), K(tmp_out)); } } } } } LOG_DEBUG("sin done", K(out)); return ret; } int ObNumber::taylor_series_cos_(const ObNumber& transformed_x, ObNumber& out, ObIAllocator& allocator, const ObNumber& range_low, const ObNumber& range_high) const { int ret = OB_SUCCESS; if (!(range_low <= transformed_x && transformed_x <= range_high)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("transform x before do taylor series expansion", K(transformed_x)); } else { // remember to change this const int64_t LOCAL_ALLOC_TIMES = 6; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); ObNumber iter_result; ObNumber divisor; ObNumber square_x; ObNumber two; ObNumber one = ObNumber::get_positive_one(); ObNumber tmp_out; if (OB_FAIL(square_x.from(transformed_x, local_alloc))) { LOG_WARN("square_x.from failed", K(square_x), K(transformed_x), K(ret)); } else if (OB_FAIL(square_x.mul_v3(transformed_x, square_x, local_alloc, true, false))) { LOG_WARN("square_x.mul failed", K(square_x), K(transformed_x), K(ret)); } else if (OB_FAIL(two.from(static_cast(2), local_alloc))) { LOG_WARN("two.from(2) failed", K(ret)); } else if (OB_FAIL(divisor.from(two, local_alloc))) { LOG_WARN("divisor.from(1) failed", K(divisor), K(ret)); } else if (OB_FAIL(square_x.div_v3(two, iter_result, local_alloc, ObNumber::OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("square_x.div_v3(two) failed", K(square_x), K(ret)); } else if (OB_FAIL(one.sub_v3(iter_result, tmp_out, local_alloc, true, false))) { LOG_WARN("one.sub_v3(iter_result) failed", K(iter_result), K(one), K(ret)); } else { size_t idx = 2; size_t start_div_num = 3; const int64_t LOCAL_ALLOC_TIMES_FOR_LOOP = 4; const int64_t LOCAL_BUF_SIZE_FOR_LOOP = LOCAL_ALLOC_TIMES_FOR_LOOP * MAX_CALC_BYTE_LEN; char local_buf_for_loop_1[LOCAL_BUF_SIZE_FOR_LOOP]; char local_buf_for_loop_2[LOCAL_BUF_SIZE_FOR_LOOP]; ObDataBuffer local_alloc_for_loop_1(local_buf_for_loop_1, LOCAL_BUF_SIZE_FOR_LOOP); ObDataBuffer local_alloc_for_loop_2(local_buf_for_loop_2, LOCAL_BUF_SIZE_FOR_LOOP); LOG_DEBUG("before while", K(iter_result), K(tmp_out), K(square_x), K(divisor)); while (OB_SUCC(ret) && (false == iter_result.is_zero())) { if (OB_FAIL(iter_result.mul_v3(square_x, iter_result, local_alloc_for_loop_1, true, false))) { LOG_WARN("iter_result.mul_v3(square_x) failed", K(ret), K(iter_result)); } else if (OB_FAIL(simple_factorial_for_sincos_(start_div_num, local_alloc_for_loop_1, divisor))) { LOG_WARN("simple_factorial_for_sincos_(start_div_num) failed", K(ret)); } else if (OB_FAIL(iter_result.div_v3( divisor, iter_result, local_alloc_for_loop_1, ObNumber::OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("iter_result.div_v3(divisor) failed", K(ret), K(iter_result), K(divisor)); } else { if (idx & 1) { // odd if (OB_FAIL(tmp_out.sub_v3(iter_result, tmp_out, local_alloc_for_loop_1, true, false))) { LOG_WARN("tmp_out.sub_v3(iter_result) failed", K(ret), K(tmp_out), K(iter_result)); } } else { if (OB_FAIL(tmp_out.add_v3(iter_result, tmp_out, local_alloc_for_loop_1, true, false))) { LOG_WARN("tmp_out.add_v3(iter_result) failed", K(ret), K(tmp_out), K(iter_result)); } } LOG_DEBUG("iteration computing", K(idx), K(tmp_out)); local_alloc_for_loop_2.free(); std::swap(local_alloc_for_loop_1, local_alloc_for_loop_2); idx += 1; start_div_num += 2; } } LOG_DEBUG("iteration done", K(tmp_out)); if (OB_SUCC(ret)) { if (OB_FAIL(out.from(tmp_out, allocator))) { LOG_WARN("out.from(tmp_out) failed", K(out), K(tmp_out)); } } } } return ret; } int ObNumber::cos(ObNumber& out, ObIAllocator& allocator, const bool do_rounding) const { int ret = OB_SUCCESS; if (is_zero()) { if (OB_FAIL(out.from(static_cast(1), allocator))) { LOG_WARN("out.from(1) failed", K(ret)); } } else { // remember to change this const int64_t LOCAL_ALLOC_TIMES = 10; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); bool neg = false; ObNumber x = *this; ObNumber pi; ObNumber tmp_out; ObNumber half_pi; // pi/2 ObNumber double_pi; // 2pi ObNumber range_low; // -pi/2 ObNumber range_high; // 3pi/2 ObNumber transformed_x; if (x.is_negative()) { if (OB_FAIL(x.negate(x, local_alloc))) { LOG_WARN("x.negate failed", K(ret), K(x)); } } if (OB_SUCC(ret)) { if (OB_FAIL(get_npi_(static_cast(-1) / 2, range_low, local_alloc, false))) { LOG_WARN("get_npi_(-1/2) failed", K(ret)); } else if (OB_FAIL(get_npi_(static_cast(1) / 2, half_pi, local_alloc, false))) { LOG_WARN("get_npi_(1/2) failed", K(ret)); } else if (OB_FAIL(get_npi_(static_cast(3) / 2, range_high, local_alloc, false))) { LOG_WARN("get_npi_(3/2) failed", K(ret)); } else if (OB_FAIL(get_npi_(static_cast(2), double_pi, local_alloc, false))) { LOG_WARN("get_npi_(2) failed", K(ret)); } else if (OB_FAIL(get_npi_(static_cast(1), pi, local_alloc, false))) { LOG_WARN("get_npi_(1) failed", K(ret)); } else { if (range_low <= x && x <= range_high) { if (OB_FAIL(transformed_x.from(x, local_alloc))) { LOG_WARN("transformed_x.from(x) failed", K(ret), K(transformed_x)); } } else { if (OB_FAIL(x.rem(double_pi, transformed_x, local_alloc))) { LOG_WARN("x.rem(double_pi) failed", K(ret), K(x), K(double_pi)); } else if (range_high < transformed_x) { if (OB_FAIL(transformed_x.sub_v3(double_pi, transformed_x, local_alloc, true, false))) { LOG_WARN("transformed_x.sub_v3(double_pi) failed", K(ret), K(transformed_x), K(double_pi)); } } } if (OB_SUCC(ret)) { // transformed_x no in[-pi/2, 3pi/2] // make in [-pi/2, pi/2] if (half_pi < transformed_x) { neg = !neg; if (OB_FAIL(transformed_x.sub_v3(pi, transformed_x, local_alloc, true, false))) { LOG_WARN("transformed_x.sub_v3(pi) failed", K(ret), K(transformed_x), K(pi)); } } } LOG_DEBUG("transform x done, starto taylor series expansion", K(double_pi), K(range_low), K(range_high), K(transformed_x), K(x), K(tmp_out)); if (OB_SUCC(ret)) { if (OB_FAIL(taylor_series_cos_(transformed_x, tmp_out, local_alloc, range_low, half_pi))) { LOG_WARN("taylor_series_cos_(transformed_x) failed", K(ret), K(transformed_x), K(tmp_out)); } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(tmp_out.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(tmp_out)); } } if (OB_SUCC(ret)) { if (neg) { if (OB_FAIL(tmp_out.negate(tmp_out, local_alloc))) { LOG_WARN("tmp_out.negate() failed", K(ret), K(tmp_out)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(out.from(tmp_out, allocator))) { LOG_WARN("out.from(tmp_out) failed", K(ret), K(tmp_out)); } } } } } } } return ret; } // tan = sin/cos int ObNumber::tan(ObNumber& out, ObIAllocator& allocator, const bool do_rounding) const { int ret = OB_SUCCESS; // remember to change this const int64_t LOCAL_ALLOC_TIMES = 3; const int64_t LOCAL_BUF_SIZE = LOCAL_ALLOC_TIMES * MAX_CALC_BYTE_LEN; char local_buf[LOCAL_BUF_SIZE]; ObDataBuffer local_alloc(local_buf, LOCAL_BUF_SIZE); bool sin_is_zero = false; bool cos_is_zero = false; ObNumber sin_out; ObNumber cos_out; ObNumber tmp_out; if (OB_FAIL(sin(sin_out, local_alloc, false))) { LOG_WARN("sin(x) failed", K(*this), K(ret)); } else if (sin_out.is_zero()) { sin_is_zero = true; } if (OB_SUCC(ret) && !sin_is_zero) { if (OB_FAIL(cos(cos_out, local_alloc, false))) { LOG_WARN("cos(x) failed", K(*this), K(ret)); } else if (cos_out.is_zero()) { cos_is_zero = true; } } LOG_DEBUG("start to calc sin/cos", K(*this), K(sin_out), K(cos_out), K(sin_is_zero), K(cos_is_zero)); if (OB_SUCC(ret)) { if (sin_is_zero) { out.set_zero(); } else if (cos_is_zero) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("cos(x) is zero", K(*this), K(ret)); } else { if (OB_FAIL(sin_out.div_v3(cos_out, tmp_out, local_alloc, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("sin/cos failed", K(sin_out), K(cos_out), K(ret)); } else if (do_rounding) { if (OB_FAIL(tmp_out.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("tmp_out.round_scale_v3_() fail", K(ret), K(tmp_out)); } } if (OB_SUCC(ret)) { if (OB_FAIL(out.from(tmp_out, allocator))) { LOG_WARN("out.from(tmp_out) failed", K(ret), K(tmp_out)); } } } } return ret; } // asin(x) = atan(x/sqrt(1-x^2)) int ObNumber::asin(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t LOCAL_ALLOCATE_TIME = 8; const char half_pi_buf[] = "1.57079632679489661923132169163975144209858469968755291048747229615"; char buf_alloc_local[ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME]; ObDataBuffer allocator_local(buf_alloc_local, ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME); ObNumber res; ObNumber one; if (OB_FAIL(one.from(static_cast(1), allocator_local))) { LOG_WARN("create const one failed", K(one), K(ret)); } else if (abs_compare(one) >= 0) { if (OB_UNLIKELY(1 == abs_compare(one))) { ret = OB_ERROR_OUT_OF_RANGE; LOG_WARN("parameter abs larger than 1", K(ret)); } else if (0 == compare(one)) { if (OB_FAIL(res.from(half_pi_buf, allocator, NULL, NULL, false))) { LOG_WARN("res from pi/2 failed", K(res), K(ret)); } } else { if (OB_FAIL(res.from(half_pi_buf, allocator_local, NULL, NULL, false))) { LOG_WARN("res from pi/2 failed", K(res), K(ret)); } else if (OB_FAIL(res.negate(res, allocator))) { LOG_WARN("res from pi/2 negate failed", K(res), K(ret)); } } } else { bool reduction = false; ObNumber atan_arg; if (OB_FAIL(mul_v3(*this, atan_arg, allocator_local, true, false))) { LOG_WARN("*this mul *this failed", K(*this), K(atan_arg), K(ret)); } else if (OB_FAIL(one.sub_v3(atan_arg, atan_arg, allocator_local, true, false))) { LOG_WARN("one sub atan_arg failed", K(one), K(atan_arg), K(ret)); } else if (OB_FAIL(atan_arg.sqrt(atan_arg, allocator_local, false))) { LOG_WARN("atan_arg sqrt failed", K(atan_arg), K(ret)); } else if (OB_FAIL(div_v3(atan_arg, atan_arg, allocator_local, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("*this div atan_arg failed", K(*this), K(atan_arg), K(ret)); } else if (OB_FAIL(atan_arg.atan(res, allocator, false))) { LOG_WARN("atan_arg atan failed", K(atan_arg), K(ret)); } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "asin [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } // acos(x) = pi/2 - asin(x) int ObNumber::acos(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t LOCAL_ALLOCATE_TIME = 2; const char half_pi_buf[] = "1.57079632679489661923132169163975144209858469968755291048747229615"; char buf_alloc_local[ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME]; ObDataBuffer allocator_local(buf_alloc_local, ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME); ObNumber res; if (OB_UNLIKELY((*this) > static_cast(1) || (*this) < static_cast(-1))) { ret = OB_ERROR_OUT_OF_RANGE; LOG_WARN("parameter abs larger than 1", K(ret)); } else if ((*this) == static_cast(1)) { if (OB_FAIL(res.from(static_cast(0), allocator))) { LOG_WARN("res from const 1 failed", K(res), K(ret)); } } else { ObNumber half_pi; if (OB_FAIL(half_pi.from(half_pi_buf, allocator_local, NULL, NULL, false))) { LOG_WARN("half_pi from const pi/2 failed", K(half_pi), K(ret)); } else if (OB_FAIL(asin(res, allocator_local, false))) { LOG_WARN("res=this->asin failed", K(*this), K(res), K(ret)); } else if (OB_FAIL(half_pi.sub_v3(res, res, allocator, true, false))) { LOG_WARN("res = half_pi sub res failed", K(res), K(half_pi), K(ret)); } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "acos [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } // parameter reduction : atan(x) = 2atan(x/(1+sqrt(1+x^2))) // taylor series: atan(x) = x-(x^3)/3+(x^5)/5-(x^7)/7+... when |x|<1 int ObNumber::atan(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t MAX_LOOP_ALLOCATE_TIME = 5; const int64_t MAX_TAYLOR_SERIES_COUNT = 200; const char PARAM_MAX_VALUE[5] = "0.15"; char buf_alloc_doublex[ObNumber::MAX_BYTE_LEN]; char buf_alloc_this[ObNumber::MAX_BYTE_LEN]; char buf_alloc_res[ObNumber::MAX_BYTE_LEN]; char buf_alloc_tmp[ObNumber::MAX_BYTE_LEN]; char buf_alloc_iter1[ObNumber::MAX_BYTE_LEN * MAX_LOOP_ALLOCATE_TIME]; char buf_alloc_iter2[ObNumber::MAX_BYTE_LEN]; char buf_alloc_const1[ObNumber::MAX_BYTE_LEN]; char buf_alloc_const2[ObNumber::MAX_BYTE_LEN]; ObDataBuffer allocator_doublex(buf_alloc_doublex, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_this(buf_alloc_this, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_res(buf_alloc_res, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_tmp(buf_alloc_tmp, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_iter1(buf_alloc_iter1, ObNumber::MAX_BYTE_LEN * MAX_LOOP_ALLOCATE_TIME); ObDataBuffer allocator_iter2(buf_alloc_iter2, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_const1(buf_alloc_const1, ObNumber::MAX_BYTE_LEN); ObDataBuffer allocator_const2(buf_alloc_const2, ObNumber::MAX_BYTE_LEN); ObNumber res; ObNumber copy_this; ObNumber param_bound; const char half_pi_buf[] = "1.57079632679489661923132169163975144209858469968755291048747229615"; if (OB_FAIL(res.from(static_cast(0), allocator_res))) { LOG_WARN("res from const 0 failed", K(res), K(ret)); } else if (OB_FAIL(param_bound.from(PARAM_MAX_VALUE, allocator_const1))) { LOG_WARN("create const 0.5 failed", K(param_bound), K(ret)); } else if (OB_FAIL(copy_this.from(*this, allocator_this))) { LOG_WARN("copy *this failed", K(copy_this), K(ret)); } else { ObNumber one; ObNumber tmp; uint8_t reduction_count = 0; // parameter reduction: arctan x = 2arctan(x/(1+sqrt(1+x*x))) while (OB_SUCC(ret) && 1 == copy_this.abs_compare(param_bound)) { if (0 == reduction_count && OB_FAIL(one.from(static_cast(1), allocator_const2))) { LOG_WARN("create const 1 failed", K(one), K(ret)); } else if (OB_FAIL(tmp.from(copy_this, allocator_iter1))) { LOG_WARN("tmp copy from copy_this failed", K(copy_this), K(tmp), K(ret)); } else if (OB_FAIL(tmp.mul_v3(copy_this, tmp, allocator_iter1, true, false))) { if (OB_INTEGER_PRECISION_OVERFLOW == ret) { ret = OB_SUCCESS; copy_this.set_zero(); allocator_res.free(); if (OB_FAIL(res.from(half_pi_buf, allocator_res, NULL, NULL, false))) { LOG_WARN("res from pi/2 failed", K(res), K(ret)); } else if (is_negative()) { res = res.negate(); } } else { LOG_WARN("tmp = tmp mul copy_this failed", K(copy_this), K(tmp), K(ret)); } } else { if (OB_FAIL(tmp.add_v3(one, tmp, allocator_iter1, true, false))) { LOG_WARN("tmp add one failed", K(copy_this), K(tmp), K(one), K(ret)); } else if (OB_FAIL(tmp.sqrt(tmp, allocator_iter1, false))) { LOG_WARN("tmp sqrt failed", K(copy_this), K(tmp), K(ret)); } else if (OB_FAIL(tmp.add_v3(one, tmp, allocator_iter1, true, false))) { LOG_WARN("tmp add one failed", K(copy_this), K(tmp), K(one), K(ret)); } else if (OB_FAIL(copy_this.div_v3(tmp, copy_this, allocator_tmp, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("copy_this div tmp failed", K(copy_this), K(tmp), K(ret)); } else { std::swap(allocator_tmp, allocator_this); allocator_tmp.free(); allocator_iter1.free(); reduction_count++; } } } ObNumber doublex; ObNumber taylor_series; ObNumber iter_const; int64_t count = 0; allocator_const1.free(); // taylor series: atan(x) = x-(x^3)/3+(x^5)/5-(x^7)/7+... when |x|<1 if (OB_FAIL(taylor_series.from(copy_this, allocator_iter2))) { LOG_WARN("taylor series from copy_this failed", K(copy_this), K(taylor_series), K(ret)); } else if (OB_FAIL(copy_this.mul_v3(copy_this, doublex, allocator_doublex, true, false))) { LOG_WARN("doublex = copy_this*copy_this failed", K(copy_this), K(doublex), K(ret)); } else if (OB_FAIL(iter_const.from(static_cast(1), allocator_const1))) { LOG_WARN("iter_const from 1 failed", K(iter_const), K(ret)); } else { while (OB_SUCC(ret) && !taylor_series.is_zero() && count < MAX_TAYLOR_SERIES_COUNT) { if (OB_FAIL(res.add_v3(taylor_series, res, allocator_tmp, true, false))) { LOG_WARN("res add taylor failed", K(res), K(taylor_series), K(ret)); } else if (OB_FAIL(taylor_series.mul_v3(iter_const, taylor_series, allocator_iter1, true, false))) { LOG_WARN("taylor_series mul iter_const failed", K(taylor_series), K(iter_const), K(ret)); } else { std::swap(allocator_tmp, allocator_res); allocator_tmp.free(); allocator_iter2.free(); allocator_const1.free(); count++; if (OB_FAIL(iter_const.from(static_cast(2 * count + 1), allocator_const1))) { LOG_WARN("iter_const from 2*count+1 failed", K(count), K(iter_const), K(ret)); } else if (OB_FAIL(taylor_series.div_v3( iter_const, taylor_series, allocator_iter1, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("taylor_series div iter_const failed", K(taylor_series), K(iter_const), K(ret)); } else if (OB_FAIL(taylor_series.mul_v3(doublex, taylor_series, allocator_iter1, true, false))) { LOG_WARN("taylor_series mul doublex failed", K(taylor_series), K(doublex), K(ret)); } else if (OB_FAIL(taylor_series.negate(taylor_series, allocator_iter2))) { LOG_WARN("taylor_series negate failed", K(taylor_series), K(ret)); } else { allocator_iter1.free(); } } } while (OB_SUCC(ret) && reduction_count > 0) { if (OB_FAIL(res.add_v3(res, res, allocator_tmp, true, false))) { LOG_WARN("res=res+res failed", K(res), K(ret)); } else { std::swap(allocator_tmp, allocator_res); allocator_tmp.free(); reduction_count--; } } } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else if (OB_FAIL(value.from(res, allocator))) { LOG_WARN("value copy from res failed", K(ret), K(res)); } } _OB_LOG(DEBUG, "atan [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::atan2( const ObNumber& other, ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; const char half_pi_buf[] = "1.57079632679489661923132169163975144209858469968755291048747229615"; const char pi_buf[] = "3.14159265358979323846264338327950288419716939937510582097494459231"; if (is_zero()) { if (OB_UNLIKELY(other.is_zero())) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("atan2 numeric overflow", K(ret)); } else if (other.is_negative()) { if (OB_FAIL(res.from(pi_buf, allocator, NULL, NULL, false))) { LOG_WARN("res from pi failed", K(ret), K(res)); } } else if (OB_FAIL(res.from("0", allocator, NULL, NULL, false))) { LOG_WARN("res from 0 failed", K(ret), K(res)); } } else if (other.is_zero()) { if (OB_FAIL(res.from(half_pi_buf, allocator, NULL, NULL, false))) { LOG_WARN("res from pi/2 failed", K(res), K(ret)); } else if (is_negative()) { res = res.negate(); } } else { bool other_negative = other.is_negative(); int64_t buf_len = other_negative ? ObNumber::MAX_BYTE_LEN * 3 : ObNumber::MAX_BYTE_LEN; char buf_alloc1[buf_len]; ObDataBuffer allocator1(buf_alloc1, buf_len); ObNumber quotient; if (OB_FAIL(div_v3(other, quotient, allocator1, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("this div other failed", K(*this), K(other), K(ret)); } else if (OB_FAIL(quotient.atan(res, other_negative ? allocator1 : allocator, false))) { LOG_WARN("quotient atan_ failed", K(quotient), K(ret)); } else if (other_negative) { ObNumber num_pi; if (OB_FAIL(num_pi.from(pi_buf, allocator1, NULL, NULL, false))) { LOG_WARN("num from pi failed", K(ret)); } else if (is_negative() && OB_FAIL(res.sub_v3(num_pi, res, allocator, true, false))) { LOG_WARN("res sub pi failed", K(ret)); } else if (!is_negative() && OB_FAIL(res.add_v3(num_pi, res, allocator, true, false))) { LOG_WARN("res add pi failed", K(ret)); } } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "atan2 [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::add_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc augend_desc; Desc addend_desc; augend_desc.desc_ = d_.desc_; addend_desc.desc_ = other.d_.desc_; LOG_DEBUG("add_", K(ret), KPC(this), K(other)); if (is_zero()) { ret = res.deep_copy(other, allocator); } else if (other.is_zero()) { ret = res.deep_copy(*this, allocator); } else if (augend_desc.sign_ == addend_desc.sign_) { ObCalcVector augend; ObCalcVector addend; int64_t shift = exp_integer_align_(augend_desc, addend_desc); exp_shift_(shift, augend_desc); exp_shift_(shift, addend_desc); if (OB_FAIL(augend.init(augend_desc.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else if (OB_FAIL(addend.init(addend_desc.desc_, other.digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { ObCalcVector sum; int64_t sum_size = std::max(augend.size(), addend.size()) + 1; if (OB_FAIL(sum.ensure(sum_size))) { LOG_WARN("Fail to ensure sum_size", K(ret)); } else if (OB_FAIL(poly_poly_add(augend, addend, sum))) { _OB_LOG(WARN, "[%s] add [%s] fail ret=%d", to_cstring(*this), to_cstring(other), ret); } else { Desc res_desc = exp_max_(augend_desc, addend_desc); bool carried = (0 != sum.at(0)); exp_shift_(-shift + (carried ? 1 : 0), res_desc); ret = res.from_v2_(res_desc.desc_, sum, allocator); } } } else { ObNumber subtrahend; StackAllocator stack_allocator; if (OB_FAIL(other.negate(subtrahend, stack_allocator))) { _OB_LOG(WARN, "nagate [%s] fail, ret=%d", to_cstring(other), ret); } else { ret = sub_(subtrahend, res, allocator); } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "add_ [%s] + [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::sub_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc minuend_desc; Desc subtrahend_desc; minuend_desc.desc_ = d_.desc_; subtrahend_desc.desc_ = other.d_.desc_; LOG_DEBUG("sub", K(ret), KPC(this), K(other)); if (is_zero()) { ret = other.negate_(res, allocator); } else if (other.is_zero()) { ret = res.from_(*this, allocator); } else if (minuend_desc.sign_ == subtrahend_desc.sign_) { ObCalcVector minuend; ObCalcVector subtrahend; int64_t shift = exp_integer_align_(minuend_desc, subtrahend_desc); exp_shift_(shift, minuend_desc); exp_shift_(shift, subtrahend_desc); if (OB_FAIL(minuend.init(minuend_desc.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else if (OB_FAIL(subtrahend.init(subtrahend_desc.desc_, other.digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { ObCalcVector remainder; int64_t remainder_size = std::max(minuend.size(), subtrahend.size()); bool sub_negative = false; if (OB_FAIL(remainder.ensure(remainder_size))) { LOG_WARN("remainder.ensure(remainder_size) fails", K(ret)); } else if (OB_FAIL(poly_poly_sub(minuend, subtrahend, remainder, sub_negative))) { _OB_LOG(WARN, "[%s] sub [%s] fail ret=%d", to_cstring(*this), to_cstring(other), ret); } else { Desc res_desc = exp_max_(minuend_desc, subtrahend_desc); for (int64_t i = 0; i < remainder.size() - 1; ++i) { if (0 != remainder.at(i)) { break; } ++shift; } exp_shift_(-shift, res_desc); bool arg_negative = (NEGATIVE == minuend_desc.sign_); if (sub_negative == arg_negative) { res_desc.sign_ = POSITIVE; } else { res_desc.sign_ = NEGATIVE; } if (res_desc.sign_ != minuend_desc.sign_) { res_desc.exp_ = (0x7f & ~res_desc.exp_); ++res_desc.exp_; } ret = res.from_v2_(res_desc.desc_, remainder, allocator); } } } else { ObNumber addend; StackAllocator stack_allocator; if (OB_FAIL(other.negate(addend, stack_allocator))) { _OB_LOG(WARN, "nagate [%s] fail, ret=%d", to_cstring(other), ret); } else { ret = add_(addend, res, allocator); } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "sub_ [%s] - [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::calc_desc_and_check_(const uint32_t base_desc, Desc& desc, int64_t exp, uint8_t len) const { int ret = OB_SUCCESS; Desc d; d.desc_ = base_desc; d.len_ = len; d.cap_ = len; d.exp_ = 0x7f & (uint8_t)(EXP_ZERO + exp); if (d.sign_ == NEGATIVE) { d.exp_ = (0x7f & (~d.exp_)); ++d.exp_; } if (OB_FAIL(exp_check_(d, lib::is_oracle_mode()))) { } else { desc = d; } return ret; } int ObNumber::add_v2_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc augend_desc; Desc addend_desc; augend_desc.desc_ = d_.desc_; addend_desc.desc_ = other.d_.desc_; LOG_DEBUG("add_v2_", K(ret), KPC(this), K(other)); if (is_zero()) { ret = res.deep_copy(other, allocator); } else if (other.is_zero()) { ret = res.deep_copy(*this, allocator); } else if (augend_desc.sign_ == addend_desc.sign_) { int64_t augend_exp = get_decode_exp(augend_desc.desc_); int64_t addend_exp = get_decode_exp(addend_desc.desc_); if (augend_exp >= addend_exp + OB_MAX_DECIMAL_DIGIT) { ret = res.deep_copy(*this, allocator); } else if (addend_exp >= augend_exp + OB_MAX_DECIMAL_DIGIT) { ret = res.deep_copy(other, allocator); } else { int64_t sum_exp = std::max(augend_exp, addend_exp); int32_t offset = 0; uint32_t* augend_digits = digits_; uint32_t* addend_digits = other.digits_; uint32_t sum_digits[OB_CALC_BUFFER_SIZE] = {}; for (int64_t i = 1, curr_exp = sum_exp, augend_id = 0, addend_id = 0; i <= OB_MAX_DECIMAL_DIGIT; ++i, --curr_exp) { uint32_t& tmp_digit = sum_digits[i]; if (curr_exp == augend_exp && augend_id < augend_desc.len_) { tmp_digit += augend_digits[augend_id]; --augend_exp; ++augend_id; } if (curr_exp == addend_exp && addend_id < addend_desc.len_) { tmp_digit += addend_digits[addend_id]; --addend_exp; ++addend_id; } // LOG_DEBUG("add_v2 ", K(sum_digits[i]), K(i), K(curr_exp), K(augend_exp), K(augend_id), K(addend_exp), // K(addend_id)); } for (int64_t i = OB_MAX_DECIMAL_DIGIT; i > 0; --i) { if (sum_digits[i] >= BASE) { sum_digits[i] -= BASE; ++sum_digits[i - 1]; } } if (sum_digits[0] != 0) { offset = 0; ++sum_exp; // normalize_digit_(sum_digits, OB_MAX_DECIMAL_DIGIT); } else { offset = 1; } uint8_t len = OB_MAX_DECIMAL_DIGIT; while (len >= offset && sum_digits[len] == 0) { --len; } len += (1 - offset); Desc sum_desc; uint32_t* digit_mem = NULL; if (OB_FAIL(calc_desc_and_check_(d_.desc_, sum_desc, sum_exp, len))) { LOG_WARN("fail to calc_desc_and_check_", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * len); res.assign(sum_desc.desc_, digit_mem); } } } else { ObNumber subtrahend = other.negate(); ret = sub_v2_(subtrahend, res, allocator); } if (OB_SUCC(ret)) { if (OB_FAIL(res.round_scale_v2_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "add_v2 [%s] + [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::add_v3(const ObNumber& other, ObNumber& value, ObIAllocator& allocator, const bool strict_mode /*true*/, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; const bool use_oracle_mode = is_oracle_mode(); LOG_DEBUG("add_v3", K(ret), KPC(this), K(other)); if (OB_UNLIKELY(is_zero())) { ret = res.deep_copy_v3(other, allocator); } else if (OB_UNLIKELY(other.is_zero())) { ret = res.deep_copy_v3(*this, allocator); } else if (d_.sign_ == other.d_.sign_) { const int64_t this_exp = get_decode_exp(d_); const int64_t other_exp = get_decode_exp(other.d_); if (OB_UNLIKELY(this_exp >= other_exp + OB_MAX_DECIMAL_DIGIT)) { ret = res.deep_copy_v3(*this, allocator); } else if (OB_UNLIKELY(other_exp >= this_exp + OB_MAX_DECIMAL_DIGIT)) { ret = res.deep_copy_v3(other, allocator); } else { Desc augend_desc(d_.desc_); Desc addend_desc(other.d_.desc_); int64_t sum_exp = this_exp; int64_t augend_exp = this_exp; int64_t addend_exp = other_exp; uint32_t* augend_digits = digits_; uint32_t* addend_digits = other.digits_; if (this_exp < other_exp || (this_exp == other_exp && d_.len_ < other.d_.len_)) { // make augend is always the larger expr one augend_desc.desc_ = other.d_.desc_; addend_desc.desc_ = d_.desc_; augend_exp = other_exp; addend_exp = this_exp; augend_digits = other.digits_; addend_digits = digits_; sum_exp = other_exp; } int32_t offset = 1; uint32_t tmp_sum_digits[OB_CALC_BUFFER_SIZE]; //[0] store carry bit uint32_t* sum_digits = NULL; if (strict_mode) { sum_digits = tmp_sum_digits; } else { if (OB_ISNULL(sum_digits = (uint32_t*)allocator.alloc(sizeof(uint32_t) * OB_CALC_BUFFER_SIZE))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * OB_CALC_BUFFER_SIZE, K(ret)); } } if (OB_SUCC(ret)) { MEMSET(sum_digits, 0, sizeof(uint32_t) * OB_CALC_BUFFER_SIZE); MEMCPY(sum_digits + 1, augend_digits, min(augend_desc.len_, OB_MAX_DECIMAL_DIGIT) * sizeof(uint32_t)); // inverse traversal const int64_t cur_augend_exp = augend_exp - (augend_desc.len_ - 1); int64_t cur_addend_exp = addend_exp - (addend_desc.len_ - 1); int64_t cur_addend_id = addend_desc.len_ - 1; int64_t cur_exp = std::min(cur_augend_exp, cur_addend_exp); uint8_t sum_len = sum_exp - cur_exp + 1; if (sum_len > OB_MAX_DECIMAL_DIGIT) { const int64_t movex = sum_len - OB_MAX_DECIMAL_DIGIT; cur_exp += movex; cur_addend_exp += movex; cur_addend_id -= movex; sum_len = OB_MAX_DECIMAL_DIGIT; } uint32_t carry = 0; bool check_sum_len = true; for (int64_t i = sum_len; i > 0; --i, ++cur_exp) { uint32_t& tmp_digit = sum_digits[i]; tmp_digit += carry; if (cur_exp == cur_addend_exp && cur_addend_id >= 0) { tmp_digit += addend_digits[cur_addend_id]; ++cur_addend_exp; --cur_addend_id; } if (tmp_digit >= BASE) { tmp_digit -= BASE; carry = 1; } else { carry = 0; } if (check_sum_len) { if (0 == tmp_digit) { --sum_len; } else { check_sum_len = false; } } } if (carry != 0) { sum_digits[0] = 1; ++sum_exp; ++sum_len; offset = 0; } Desc sum_desc; uint32_t* digit_mem = NULL; if (OB_FAIL(calc_desc_and_check(d_.desc_, sum_exp, sum_len, sum_desc, use_oracle_mode))) { LOG_WARN("fail to calc_desc_and_check_", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (strict_mode) { if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, digit_mem); } } else { res.assign(sum_desc.desc_, sum_digits + offset); } } } } else { ret = sub_v3(other.negate(), res, allocator, strict_mode, do_rounding); } if (OB_SUCC(ret)) { if (do_rounding && res.need_round_after_arithmetic(use_oracle_mode) && OB_FAIL(res.round_scale_v3_(use_oracle_mode ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "add_v3 [%s] + [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::sub_v2_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc minuend_desc; Desc subtrahend_desc; minuend_desc.desc_ = d_.desc_; subtrahend_desc.desc_ = other.d_.desc_; LOG_DEBUG("sub_v2_", K(ret), KPC(this), K(other)); if (is_zero()) { ret = other.negate_v2_(res, allocator); } else if (other.is_zero()) { ret = res.deep_copy(*this, allocator); } else if (minuend_desc.sign_ == subtrahend_desc.sign_) { int64_t minuend_exp = get_decode_exp(minuend_desc.desc_); int64_t subtrahend_exp = get_decode_exp(subtrahend_desc.desc_); if (minuend_exp >= subtrahend_exp + OB_MAX_DECIMAL_DIGIT) { ret = res.deep_copy(*this, allocator); } else if (subtrahend_exp >= minuend_exp + OB_MAX_DECIMAL_DIGIT) { ret = other.negate_v2_(res, allocator); } else { int64_t sum_exp = std::max(minuend_exp, subtrahend_exp); int32_t sum_digits[OB_CALC_BUFFER_SIZE] = {}; int first_digit_flag = 0; bool arg_negative = (NEGATIVE == minuend_desc.sign_); bool sub_negative = false; uint32_t* minuend_digits = digits_; uint32_t* subtrahend_digits = other.digits_; for (int64_t i = 0, curr_exp = sum_exp, minuend_id = 0, subtrahend_id = 0; i <= OB_MAX_DECIMAL_DIGIT; ++i, --curr_exp) { int32_t& tmp_digit = sum_digits[i]; if (curr_exp == minuend_exp && minuend_id < minuend_desc.len_) { tmp_digit += minuend_digits[minuend_id]; --minuend_exp; ++minuend_id; } if (curr_exp == subtrahend_exp && subtrahend_id < subtrahend_desc.len_) { tmp_digit -= subtrahend_digits[subtrahend_id]; --subtrahend_exp; ++subtrahend_id; } if (0 == first_digit_flag && tmp_digit != 0) { first_digit_flag = (tmp_digit > 0 ? 1 : -1); } // LOG_DEBUG("sub_v2 ", K(sum_digits[i]), K(i), K(curr_exp), K(minuend_exp), K(minuend_id), // K(subtrahend_exp), K(subtrahend_id), K(first_digit_flag)); } sub_negative = (-1 == first_digit_flag); if (sub_negative) { for (int64_t i = OB_MAX_DECIMAL_DIGIT; i >= 0; --i) { int32_t& tmp_digit = sum_digits[i]; tmp_digit = 0 - tmp_digit; if (tmp_digit < 0) { tmp_digit += BASE; ++sum_digits[i - 1]; // not -1 } } } else { for (int64_t i = OB_MAX_DECIMAL_DIGIT; i >= 0; --i) { int32_t& tmp_digit = sum_digits[i]; if (tmp_digit < 0) { tmp_digit += BASE; --sum_digits[i - 1]; } } } // normalize_digit_(sum_digits, OB_MAX_DECIMAL_DIGIT); int64_t start_id = 0; for (; start_id <= OB_MAX_DECIMAL_DIGIT && sum_digits[start_id] == 0; ++start_id, --sum_exp) ; int32_t len = (OB_MAX_DECIMAL_DIGIT - start_id + 1); for (int64_t i = OB_MAX_DECIMAL_DIGIT; i >= start_id && sum_digits[i] == 0; --len, --i) ; if (start_id > OB_MAX_DECIMAL_DIGIT) { res.set_zero(); ret = OB_SUCCESS; } else { uint32_t* digit_mem = NULL; Desc sum_desc; Desc tmp_desc; tmp_desc.desc_ = d_.desc_; tmp_desc.sign_ = (arg_negative == sub_negative ? POSITIVE : NEGATIVE); if (OB_FAIL(calc_desc_and_check_(tmp_desc.desc_, sum_desc, sum_exp, len))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + start_id, sizeof(uint32_t) * len); res.assign(sum_desc.desc_, (uint32_t*)digit_mem); } } } } else { ObNumber addend = other.negate(); ret = add_v2_(addend, res, allocator); } if (OB_SUCC(ret)) { if (OB_FAIL(res.round_scale_v2_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "sub_v2 [%s] - [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::sub_v3(const ObNumber& other, ObNumber& value, ObIAllocator& allocator, const bool strict_mode /*true*/, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; const bool use_oracle_mode = is_oracle_mode(); LOG_DEBUG("sub_v3", K(ret), KPC(this), K(other)); if (OB_UNLIKELY(is_zero())) { ret = other.negate_v3_(res, allocator); } else if (OB_UNLIKELY(other.is_zero())) { ret = res.deep_copy_v3(*this, allocator); } else if (d_.sign_ == other.d_.sign_) { const int64_t this_exp = get_decode_exp(d_); const int64_t other_exp = get_decode_exp(other.d_); if (OB_UNLIKELY(this_exp >= other_exp + OB_MAX_DECIMAL_DIGIT)) { ret = res.deep_copy_v3(*this, allocator); } else if (OB_UNLIKELY(other_exp >= this_exp + OB_MAX_DECIMAL_DIGIT)) { ret = other.negate_v3_(res, allocator); } else { int64_t start_id = 0; bool sub_negative = false; bool is_equal = false; if (this_exp > other_exp) { sub_negative = false; } else if (this_exp < other_exp) { sub_negative = true; } else { const int64_t min_id = std::min(d_.len_, other.d_.len_) - 1; while (start_id <= min_id && digits_[start_id] == other.digits_[start_id]) { ++start_id; } if (start_id > min_id) { if (d_.len_ == other.d_.len_) { is_equal = true; } else { sub_negative = (d_.len_ < other.d_.len_); } } else { sub_negative = (digits_[start_id] < other.digits_[start_id]); } } // LOG_DEBUG("sub_v3", K(is_equal), K(sub_negative), K(start_id)); if (is_equal) { res.set_zero(); } else { Desc minuend_desc(d_.desc_); Desc subtrahend_desc(other.d_.desc_); int64_t minuend_exp = this_exp; int64_t subtrahend_exp = other_exp; uint32_t* minuend_digits = digits_; uint32_t* subtrahend_digits = other.digits_; if (sub_negative) { // always make the minuend is larger one minuend_desc.desc_ = other.d_.desc_; subtrahend_desc.desc_ = d_.desc_; minuend_exp = other_exp; subtrahend_exp = this_exp; minuend_digits = other.digits_; subtrahend_digits = digits_; } int32_t tmp_sum_digits[OB_CALC_BUFFER_SIZE]; int32_t* sum_digits = NULL; if (strict_mode) { sum_digits = tmp_sum_digits; } else { if (OB_ISNULL(sum_digits = (int32_t*)allocator.alloc(sizeof(uint32_t) * OB_CALC_BUFFER_SIZE))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * OB_CALC_BUFFER_SIZE, K(ret)); } } if (OB_SUCC(ret)) { MEMSET(sum_digits, 0, sizeof(uint32_t) * OB_CALC_BUFFER_SIZE); MEMCPY(sum_digits + start_id, minuend_digits + start_id, (minuend_desc.len_ - start_id) * sizeof(uint32_t)); int64_t sum_exp = minuend_exp; const int64_t cur_minuend_exp = minuend_exp - (minuend_desc.len_ - 1); int64_t cur_subtrahend_exp = subtrahend_exp - (subtrahend_desc.len_ - 1); int64_t cur_subtrahend_id = subtrahend_desc.len_ - 1; int64_t cur_exp = std::min(cur_minuend_exp, cur_subtrahend_exp); uint8_t sum_len = sum_exp - cur_exp + 1; if (sum_len > OB_MAX_DECIMAL_DIGIT) { const int64_t movex = sum_len - OB_MAX_DECIMAL_DIGIT; cur_exp += movex; cur_subtrahend_exp += movex; cur_subtrahend_id -= movex; sum_len = OB_MAX_DECIMAL_DIGIT; } // LOG_DEBUG("sub_v3", K(cur_subtrahend_exp), K(cur_subtrahend_id), K(sum_exp), K(cur_exp), // K(sum_len)); int32_t carry = 0; bool check_sum_len = true; for (int64_t i = sum_len - 1; i >= start_id; --i, ++cur_exp) { int32_t& tmp_digit = sum_digits[i]; // LOG_DEBUG("sub_v3", K(i), K(cur_exp), K(tmp_digit), K(carry), K(cur_subtrahend_exp), // K(cur_subtrahend_id), K(subtrahend_digits[cur_subtrahend_id])); tmp_digit += carry; if (cur_exp == cur_subtrahend_exp && cur_subtrahend_id >= start_id) { tmp_digit -= subtrahend_digits[cur_subtrahend_id--]; ++cur_subtrahend_exp; } if (tmp_digit < 0) { tmp_digit += BASE; carry = -1; } else { carry = 0; } if (check_sum_len) { if (0 == tmp_digit) { --sum_len; } else { check_sum_len = false; } } } sum_digits[sum_len] = BASE; // end flag int32_t* tmp_digit = sum_digits + start_id; while (0 == *tmp_digit) { ++tmp_digit; } int64_t new_start_id = tmp_digit - sum_digits; sum_len -= new_start_id; const int64_t new_sum_exp = sum_exp - new_start_id; // LOG_DEBUG("sub_v3", K(start_id), K(new_start_id), K(sum_len), K(new_sum_exp)); if (sum_len <= 0) { res.set_zero(); } else { uint32_t* digit_mem = NULL; Desc sum_desc(d_); sum_desc.sign_ = ((NEGATIVE == minuend_desc.sign_) == sub_negative ? POSITIVE : NEGATIVE); if (OB_FAIL(calc_desc_and_check(sum_desc.desc_, new_sum_exp, sum_len, sum_desc, use_oracle_mode))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (strict_mode) { if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + new_start_id, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, (uint32_t*)digit_mem); } } else { res.assign(sum_desc.desc_, (uint32_t*)(sum_digits + new_start_id)); } } } } } } else { ret = add_v3(other.negate(), res, allocator, strict_mode, do_rounding); } if (OB_SUCC(ret)) { if (do_rounding && res.need_round_after_arithmetic(use_oracle_mode) && OB_FAIL(res.round_scale_v3_(use_oracle_mode ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "sub_v3 [%s] - [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::negate_(ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; if (is_zero()) { res.set_zero(); } else { ObCalcVector cv; if (OB_FAIL(cv.init(d_.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { int64_t size2alloc = d_.len_; if (POSITIVE == d_.sign_) { res.d_.sign_ = NEGATIVE; } else { res.d_.sign_ = POSITIVE; } res.d_.exp_ = (0x7f & ~d_.exp_); ++res.d_.exp_; if (OB_ISNULL(res.digits_ = res.alloc_(allocator, size2alloc))) { _OB_LOG(WARN, "alloc digits fail, length=%ld", size2alloc); ret = OB_ALLOCATE_MEMORY_FAILED; } else if (OB_FAIL(res.normalize_(cv.get_digits(), cv.size()))) { _OB_LOG(WARN, "normalize [%s] fail ret=%d", to_cstring(res), ret); } else { // do nothing } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "negate [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::negate_v2_(ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; if (is_zero()) { res.set_zero(); } else { res = this->negate(); if (OB_ISNULL(res.digits_ = res.alloc_(allocator, d_.len_))) { ret = OB_ALLOCATE_MEMORY_FAILED; OB_LOG(WARN, "alloc digits fail", K(d_.len_), K(ret)); } else { MEMCPY(res.digits_, digits_, d_.len_ * sizeof(uint32_t)); } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "negate_v2 [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::negate_v3_(ObNumber& value, ObIAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; if (is_zero()) { res.set_zero(); } else { res = this->negate(); if (OB_ISNULL(res.digits_ = (uint32_t*)allocator.alloc(d_.len_ * sizeof(uint32_t)))) { ret = OB_ALLOCATE_MEMORY_FAILED; OB_LOG(WARN, "alloc digits fail", K(d_.len_), K(ret)); } else { MEMCPY(res.digits_, digits_, d_.len_ * sizeof(uint32_t)); } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "negate_v3 [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::mul_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc multiplicand_desc; Desc multiplier_desc; multiplicand_desc.desc_ = d_.desc_; multiplier_desc.desc_ = other.d_.desc_; if (is_zero() || other.is_zero()) { res.set_zero(); } else { ObCalcVector multiplicand; ObCalcVector multiplier; if (OB_FAIL(multiplicand.init(multiplicand_desc.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else if (OB_FAIL(multiplier.init(multiplier_desc.desc_, other.digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { ObCalcVector product; int64_t product_size = multiplicand.size() + multiplier.size(); if (OB_FAIL(product.ensure(product_size))) { LOG_WARN("product.ensure(product_size) fails", K(ret)); } else if (OB_FAIL(poly_poly_mul(multiplicand, multiplier, product))) { _OB_LOG(WARN, "[%s] mul [%s] fail, ret=%d", to_cstring(*this), to_cstring(other), ret); } else { Desc res_desc = exp_mul_(multiplicand_desc, multiplier_desc); bool carried = (0 != product.at(0)); exp_shift_((carried ? 1 : 0), res_desc); ret = res.from_v2_(res_desc.desc_, product, allocator); } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "mul [%s] * [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::mul_v2_( const ObNumber& other, ObNumber& value, IAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; Desc multiplicand_desc; Desc multiplier_desc; multiplicand_desc.desc_ = d_.desc_; multiplier_desc.desc_ = other.d_.desc_; LOG_DEBUG("mul_v2_", K(ret), KPC(this), K(other)); if (is_zero() || other.is_zero()) { res.set_zero(); } else { int64_t sum_exp = get_decode_exp(multiplicand_desc.desc_) + get_decode_exp(multiplier_desc.desc_); uint32_t* multiplicand_digits = digits_; uint32_t* multiplier_digits = other.digits_; uint64_t sum_digits[OB_MULT_BUFFER_SIZE] = {}; int64_t multiplicand_len = multiplicand_desc.len_; int64_t multiplier_len = multiplier_desc.len_; int64_t sum_len = multiplicand_len + multiplier_len; int64_t digits_len = 0; int offset = 0; for (int64_t i = 0; i < multiplicand_len; ++i) { for (int64_t j = 0; j < multiplier_len; ++j) { int64_t k = i + j + 1; sum_digits[k] += (uint64_t)multiplicand_digits[i] * multiplier_digits[j]; if (sum_digits[k] >= CARRY_BOUND) { uint64_t carry = 0; for (int64_t id = k; id >= 0; --id) { uint64_t tmp = carry + sum_digits[id]; carry = tmp / BASE; sum_digits[id] = tmp - carry * BASE; if (0 == carry) { break; } } } } } for (int64_t i = sum_len - 1; i >= 1; --i) { if (sum_digits[i] >= BASE) { int64_t tmp = sum_digits[i] / BASE; sum_digits[i] -= tmp * BASE; sum_digits[i - 1] += tmp; } } if (sum_digits[0] != 0) { ++sum_exp; } else { offset = 1; } while ((sum_len - 1) >= offset && sum_digits[sum_len - 1] == 0) { --sum_len; } digits_len = sum_len - offset; if (digits_len > OB_MAX_DECIMAL_DIGIT) { digits_len = OB_MAX_DECIMAL_DIGIT; // normalize_digit_(sum_digits + offset, OB_MAX_DECIMAL_DIGIT); } Desc sum_desc, tmp_desc; tmp_desc.desc_ = d_.desc_; tmp_desc.sign_ = (multiplicand_desc.sign_ == multiplier_desc.sign_ ? POSITIVE : NEGATIVE); uint32_t* digit_mem = NULL; if (OB_FAIL(calc_desc_and_check_(tmp_desc.desc_, sum_desc, sum_exp, (uint8_t)digits_len))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * digits_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * digits_len, K(ret)); } else { for (int64_t i = 0; i < digits_len; ++i) { digit_mem[i] = static_cast(sum_digits[i + offset]); } res.assign(sum_desc.desc_, digit_mem); } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } else { value = res; } } _OB_LOG(DEBUG, "mul_v2 [%s] * [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::mul_v3(const ObNumber& other, ObNumber& value, ObIAllocator& allocator, const bool strict_mode /*true*/, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; const bool use_oracle_mode = is_oracle_mode(); LOG_DEBUG("mul_v3_", K(ret), KPC(this), K(other)); if (is_zero() || other.is_zero()) { res.set_zero(); } else { Desc multiplicand_desc(d_.desc_); Desc multiplier_desc(other.d_.desc_); const uint32_t* multiplicand_digits = digits_; const uint32_t* multiplier_digits = other.digits_; uint64_t sum_digits[OB_MULT_BUFFER_SIZE] = {}; int64_t multiplicand_len = multiplicand_desc.len_; int64_t multiplier_len = multiplier_desc.len_; // swap if (d_.len_ > other.d_.len_) { multiplicand_digits = other.digits_; multiplier_digits = digits_; multiplicand_len = multiplier_desc.len_; multiplier_len = multiplicand_desc.len_; } int64_t sum_exp = get_decode_exp(multiplicand_desc.desc_) + get_decode_exp(multiplier_desc.desc_); int64_t sum_len = multiplier_desc.len_ + multiplicand_desc.len_; int64_t digits_len = 0; int offset = 0; bool check_sum_len = true; uint32_t tmp_res_digits[OB_CALC_BUFFER_SIZE] = {0}; uint32_t* res_digits = NULL; if (strict_mode) { res_digits = tmp_res_digits; } else { if (OB_ISNULL(res_digits = (uint32_t*)allocator.alloc(sizeof(uint32_t) * OB_CALC_BUFFER_SIZE))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * OB_CALC_BUFFER_SIZE, K(ret)); } } if (OB_SUCC(ret)) { if (sum_len <= OB_MAX_DECIMAL_DIGIT) { MEMSET(res_digits + sum_len, 0, sizeof(uint32_t) * (OB_MAX_DECIMAL_DIGIT - sum_len + 1)); } const uint32_t* multiplicand_di = multiplicand_digits; for (int64_t i = 0; i < multiplicand_len; ++i) { const uint64_t tmp_multiplicand_di = static_cast(*multiplicand_di++); const uint32_t* tmp_multiplier_di = multiplier_digits; uint64_t* sum_di = sum_digits + (i + 1); for (int64_t j = 0; j < multiplier_len; ++j) { (*sum_di++) += tmp_multiplicand_di * (*tmp_multiplier_di++); } } int64_t carry = 0; for (int64_t i = sum_len - 1; i >= 0; --i) { uint64_t tmp_digit = sum_digits[i]; tmp_digit += carry; if (tmp_digit >= BASE) { carry = tmp_digit / BASE; tmp_digit -= carry * BASE; } else { carry = 0; } if (check_sum_len) { if (0 == tmp_digit) { --sum_len; } else { check_sum_len = false; } } if (i <= OB_MAX_DECIMAL_DIGIT) { res_digits[i] = static_cast(tmp_digit); } } if (res_digits[0] != 0) { ++sum_exp; } else { offset = 1; } digits_len = sum_len - offset; if (digits_len > OB_MAX_DECIMAL_DIGIT) { digits_len = OB_MAX_DECIMAL_DIGIT; } Desc sum_desc(d_); sum_desc.sign_ = (multiplicand_desc.sign_ == multiplier_desc.sign_ ? POSITIVE : NEGATIVE); uint32_t* digit_mem = NULL; if (OB_FAIL(calc_desc_and_check(sum_desc.desc_, sum_exp, (uint8_t)digits_len, sum_desc, use_oracle_mode))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (strict_mode) { if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * digits_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * digits_len, K(ret)); } else { MEMCPY(digit_mem, res_digits + offset, sizeof(uint32_t) * digits_len); res.assign(sum_desc.desc_, digit_mem); } } else { res.assign(sum_desc.desc_, res_digits + offset); } } } if (OB_SUCC(ret)) { if (do_rounding && res.need_round_after_arithmetic(use_oracle_mode) && OB_FAIL(res.round_scale_v3_(use_oracle_mode ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "mul_v3 [%s] * [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::div_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc dividend_desc; Desc divisor_desc; dividend_desc.desc_ = d_.desc_; divisor_desc.desc_ = other.d_.desc_; if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else { ObCalcVector dividend; ObCalcVector divisor; int64_t shift = get_extend_length_remainder_(dividend_desc, divisor_desc); shift = (MAX_STORE_LEN <= shift) ? shift : (MAX_STORE_LEN - shift); shift += get_decimal_extend_length_(dividend_desc); exp_shift_(shift, dividend_desc); if (OB_FAIL(dividend.init(dividend_desc.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else if (OB_FAIL(divisor.init(divisor_desc.desc_, other.digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { ObCalcVector quotient; ObCalcVector remainder; int64_t quotient_size = dividend.size() - divisor.size() + 1; int64_t remainder_size = divisor.size(); if (OB_FAIL(quotient.ensure(quotient_size))) { LOG_WARN("quotient.ensure(quotient_size) fails", K(ret)); } else if (OB_FAIL(remainder.ensure(remainder_size))) { LOG_WARN("remainder.ensure(remainder_size) fails", K(ret)); } else if (OB_FAIL(poly_poly_div(dividend, divisor, quotient, remainder))) { _OB_LOG(WARN, "[%s] div [%s] fail ret=%d", to_cstring(*this), to_cstring(other), ret); } else { Desc res_desc = exp_div_(dividend_desc, divisor_desc); for (int64_t i = 0; i < quotient.size(); ++i) { if (0 != quotient.at(i)) { break; } ++shift; } exp_shift_(-shift, res_desc); ret = res.from_v2_(res_desc.desc_, quotient, allocator); } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "div: [%s] / [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::div_v2_(const ObNumber& other, ObNumber& value, IAllocator& allocator, const int32_t qscale, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; Desc dividend_desc; Desc divisor_desc; dividend_desc.desc_ = d_.desc_; divisor_desc.desc_ = other.d_.desc_; LOG_DEBUG("div_v2_", K(ret), KPC(this), K(other)); if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else { /* remove ObCalcVector */ ObDivArray dividend, divisor, quotient; int32_t extend_len = other.d_.len_ + qscale; extend_len = std::min(extend_len, +OB_DIV_BUFFER_SIZE); dividend.from(digits_, d_.len_, std::min(+OB_DIV_BUFFER_SIZE, extend_len)); divisor.from(other.digits_, other.d_.len_, other.d_.len_); dividend.div(divisor, quotient); if (quotient.is_zero()) { res.set_zero(); } else { int64_t sum_exp = get_decode_exp(dividend_desc.desc_) - get_decode_exp(divisor_desc.desc_); uint32_t sum_digits[OB_MULT_BUFFER_SIZE] = {}; quotient.get_uint32_digits(sum_digits, OB_MULT_BUFFER_SIZE); int32_t offset = 0; int32_t sum_len = quotient.len_; while (offset < quotient.len_ && sum_digits[offset] == 0) { ++offset; --sum_exp; --sum_len; } if (sum_len > OB_MAX_DECIMAL_DIGIT) { sum_len = OB_MAX_DECIMAL_DIGIT; // normalize_digit_(sum_digits + offset, sum_len); } int32_t end = offset + sum_len - 1; // remove tailing zero while (sum_digits[end] == 0) { --end; --sum_len; } Desc tmp_desc, sum_desc; uint32_t* digit_mem = NULL; tmp_desc.desc_ = d_.desc_; tmp_desc.sign_ = (dividend_desc.sign_ == divisor_desc.sign_ ? POSITIVE : NEGATIVE); if (OB_FAIL(calc_desc_and_check_(tmp_desc.desc_, sum_desc, sum_exp, (uint8_t)sum_len))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, digit_mem); } } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } else { value = res; } } _OB_LOG(DEBUG, "div_v2: [%s] / [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::div_v3(const ObNumber& other, ObNumber& value, ObIAllocator& allocator, const int32_t qscale /*OB_MAX_DECIMAL_DIGIT*/, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; ObNumber res; const bool use_oracle_mode = is_oracle_mode(); LOG_DEBUG("div_v3_", K(ret), KPC(this), K(other)); if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else { Desc dividend_desc(d_); Desc divisor_desc(other.d_); ObDivArray dividend; ObDivArray divisor; ObDivArray quotient; int32_t extend_len = other.d_.len_ + qscale; extend_len = std::min(extend_len, +OB_DIV_BUFFER_SIZE); dividend.from(digits_, d_.len_, std::min(+OB_DIV_BUFFER_SIZE, extend_len)); divisor.from(other.digits_, other.d_.len_, other.d_.len_); dividend.div_v2(divisor, quotient); if (quotient.is_zero()) { res.set_zero(); } else { int64_t sum_exp = get_decode_exp(dividend_desc.desc_) - get_decode_exp(divisor_desc.desc_); uint32_t sum_digits[OB_MULT_BUFFER_SIZE] = {}; quotient.get_uint32_digits(sum_digits, OB_MULT_BUFFER_SIZE); int32_t offset = 0; int32_t sum_len = quotient.len_; while (offset < quotient.len_ && sum_digits[offset] == 0) { ++offset; --sum_exp; --sum_len; } if (sum_len > OB_MAX_DECIMAL_DIGIT) { sum_len = OB_MAX_DECIMAL_DIGIT; } const int32_t end = offset + sum_len - 1; // remove tailing zero uint32_t* tmp_sum_digits = sum_digits + end; while (*tmp_sum_digits == 0) { --tmp_sum_digits; } sum_len -= (sum_digits + end - tmp_sum_digits); uint32_t* digit_mem = NULL; Desc sum_desc(d_); sum_desc.sign_ = (dividend_desc.sign_ == divisor_desc.sign_ ? POSITIVE : NEGATIVE); if (OB_FAIL(calc_desc_and_check(sum_desc.desc_, sum_exp, (uint8_t)sum_len, sum_desc, use_oracle_mode))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, digit_mem); } } } if (OB_SUCC(ret)) { LOG_DEBUG("round scale before", K(res)); if (do_rounding && res.need_round_after_arithmetic(use_oracle_mode) && OB_FAIL(res.round_scale_v3_(use_oracle_mode ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "div_v3: [%s] / [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } // sinh(x)=(e^x - e^(-x)) / 2 int ObNumber::sinh(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t LOCAL_ALLOCATE_TIME = 4; char buf_alloc_local[ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME]; ObDataBuffer allocator_local(buf_alloc_local, ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME); ObNumber res; ObNumber e_power_x; ObNumber e_power_negate_x; const ObNumber const_zero_dot_five = get_positive_zero_dot_five(); if (OB_FAIL(e_power(e_power_x, allocator_local, false))) { LOG_WARN("calc power(e,x) falied", K(ret), K(*this)); } else if (e_power_x.is_zero()) { ObNumber negate_x; if (OB_FAIL(negate(negate_x, allocator_local))) { LOG_WARN("negate x failed", K(ret), K(*this)); } else if (OB_FAIL(negate_x.e_power(e_power_negate_x, allocator_local, false))) { LOG_WARN("calc power(e,-x) failed", K(ret), K(negate_x)); } else if (OB_FAIL(e_power_negate_x.mul_v3(const_zero_dot_five, res, allocator_local, true, false))) { LOG_WARN("e_power_negate_x mul 0.5 failed", K(ret), K(e_power_negate_x)); } else if (OB_FAIL(res.negate(res, allocator))) { LOG_WARN("res negate failed", K(ret), K(res)); } } else { const ObNumber const_one = get_positive_one(); if (OB_FAIL(const_one.div_v3(e_power_x, e_power_negate_x, allocator_local, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("calc power(e,-x) by 1/power(e,x) failed", K(ret), K(e_power_x)); } else if (OB_FAIL(e_power_x.sub_v3(e_power_negate_x, res, allocator_local, true, false))) { LOG_WARN("e_power_x add e_power_negate_x failed", K(ret), K(e_power_x), K(e_power_negate_x)); } else if (OB_FAIL(res.mul_v3(const_zero_dot_five, res, allocator, true, false))) { LOG_WARN("res mul 0.5 failed", K(ret), K(res)); } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "sinh [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } // cosh(x)=(e^x + e^(-x)) / 2 int ObNumber::cosh(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t LOCAL_ALLOCATE_TIME = 3; char buf_alloc_local[ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME]; ObDataBuffer allocator_local(buf_alloc_local, ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME); ObNumber res; ObNumber e_power_x; ObNumber e_power_negate_x; const ObNumber const_zero_dot_five = get_positive_zero_dot_five(); if (OB_FAIL(e_power(e_power_x, allocator_local, false))) { LOG_WARN("calc power(e,x) falied", K(ret), K(*this)); } else if (e_power_x.is_zero()) { ObNumber negate_x; if (OB_FAIL(negate(negate_x, allocator_local))) { LOG_WARN("negate x failed", K(ret), K(*this)); } else if (OB_FAIL(negate_x.e_power(e_power_negate_x, allocator_local, false))) { LOG_WARN("calc power(e,-x) failed", K(ret), K(negate_x)); } else if (OB_FAIL(e_power_negate_x.mul_v3(const_zero_dot_five, res, allocator, true, false))) { LOG_WARN("e_power_negate_x mul 0.5 failed", K(ret), K(e_power_negate_x)); } } else { const ObNumber const_one = get_positive_one(); ObNumber sum; if (OB_FAIL(const_one.div_v3(e_power_x, e_power_negate_x, allocator_local, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("calc power(e,-x) by 1/power(e,x) failed", K(ret), K(e_power_x)); } else if (OB_FAIL(e_power_x.add_v3(e_power_negate_x, sum, allocator_local, true, false))) { LOG_WARN("e_power_x add e_power_negate_x failed", K(ret), K(e_power_x), K(e_power_negate_x)); } else if (OB_FAIL(sum.mul_v3(const_zero_dot_five, res, allocator, true, false))) { LOG_WARN("sum mul 0.5 failed", K(ret), K(sum)); } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "cosh [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } // tanh(x)= sinh(x) / cosh(x) = (e^x - e^(-x)) / (e^x + e^(-x)) int ObNumber::tanh(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; const int64_t LOCAL_ALLOCATE_TIME = 4; char buf_alloc_local[ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME]; ObDataBuffer allocator_local(buf_alloc_local, ObNumber::MAX_BYTE_LEN * LOCAL_ALLOCATE_TIME); ObNumber res; ObNumber e_power_x; ObNumber e_power_negate_x; if (OB_FAIL(e_power(e_power_x, allocator_local, false))) { LOG_WARN("calc power(e,x) falied", K(ret), K(*this)); } else if (e_power_x.is_zero()) { ObNumber negate_x; if (OB_FAIL(negate(negate_x, allocator_local))) { LOG_WARN("negate x failed", K(ret), K(*this)); } else if (OB_FAIL(negate_x.e_power(e_power_negate_x, allocator_local, false))) { LOG_WARN("calc power(e,-x) failed", K(ret), K(negate_x)); } else if (OB_FAIL(res.from("-1", allocator))) { LOG_WARN("result from -1 failed", K(ret)); } } else { const ObNumber const_one = get_positive_one(); ObNumber sum; ObNumber diff; if (OB_FAIL(const_one.div_v3(e_power_x, e_power_negate_x, allocator_local, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("calc power(e,-x) by 1/power(e,x) failed", K(ret), K(e_power_x)); } else if (OB_FAIL(e_power_x.add_v3(e_power_negate_x, sum, allocator_local, true, false))) { LOG_WARN("e_power_x add e_power_negate_x failed", K(ret), K(e_power_x), K(e_power_negate_x)); } else if (OB_FAIL(e_power_x.sub_v3(e_power_negate_x, diff, allocator_local, true, false))) { LOG_WARN("e_power_x sub e_power_negate_x failed", K(ret), K(e_power_x), K(e_power_negate_x)); } else if (OB_FAIL(diff.div_v3(sum, res, allocator, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("diff div sum failed", K(ret), K(diff), K(sum)); } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(res.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("round scale fail", K(ret), K(res)); } else { value = res; } } _OB_LOG(DEBUG, "tanh [%s], ret=%d [%s]", this->format(), ret, res.format()); return ret; } int ObNumber::rem_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc dividend_desc; Desc divisor_desc; dividend_desc.desc_ = d_.desc_; divisor_desc.desc_ = other.d_.desc_; int cmp_ret = 0; if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else if (0 >= (cmp_ret = abs_compare(other))) { if (0 == cmp_ret) { res.set_zero(); } else { res.from(*this, allocator); } } else { int64_t shift = std::max(get_decimal_extend_length_(dividend_desc), get_decimal_extend_length_(divisor_desc)); exp_shift_(shift, dividend_desc); exp_shift_(shift, divisor_desc); ObCalcVector dividend; ObCalcVector divisor; if (OB_FAIL(dividend.init(dividend_desc.desc_, digits_))) { LOG_WARN("fail to assign values", K(ret)); } else if (OB_FAIL(divisor.init(divisor_desc.desc_, other.digits_))) { LOG_WARN("fail to assign values", K(ret)); } else { ObCalcVector dividend_amplify; ObCalcVector* dividend_ptr = NULL; if (dividend.size() < divisor.size()) { _OB_LOG(WARN, "dividend_size=%ld must not less than divisor_size=%ld", dividend.size(), divisor.size()); ret = OB_ERR_UNEXPECTED; } else if (dividend.size() > divisor.size()) { dividend_ptr = ÷nd; } else { ObCalcVector divisor_amplify; if (OB_FAIL(divisor_amplify.ensure(divisor.size() + 1))) { LOG_WARN("divisor_amplify.ensure() fails", K(ret)); } else if (OB_FAIL(poly_mono_mul(divisor, BASE - 1, divisor_amplify))) { _OB_LOG(WARN, "[%s] mul [%lu] fail, ret=%d", to_cstring(divisor), BASE - 1, ret); } else { int64_t sum_size = std::max(dividend.size(), divisor_amplify.size()) + 1; if (OB_FAIL(dividend_amplify.ensure(sum_size))) { LOG_WARN("ensure() fails", K(ret)); } else if (OB_FAIL(poly_poly_add(dividend, divisor_amplify, dividend_amplify))) { _OB_LOG(WARN, "[%s] add [%s] fail, ret=%d", to_cstring(dividend), to_cstring(divisor_amplify), ret); } else { dividend_ptr = ÷nd_amplify; } } } if (OB_SUCC(ret)) { ObCalcVector quotient; ObCalcVector remainder; int64_t quotient_size = dividend_ptr->size() - divisor.size() + 1; int64_t remainder_size = divisor.size(); if (OB_FAIL(quotient.ensure(quotient_size))) { LOG_WARN("ensure() fails", K(ret)); } else if (OB_FAIL(remainder.ensure(remainder_size))) { LOG_WARN("ensure() fails", K(ret)); } else if (OB_FAIL(poly_poly_div(*dividend_ptr, divisor, quotient, remainder))) { _OB_LOG(WARN, "[%s] div [%s] fail ret=%d", to_cstring(*dividend_ptr), to_cstring(divisor), ret); } else { Desc res_desc = exp_rem_(dividend_desc, divisor_desc); for (int64_t i = 0; i < remainder.size() - 1; ++i) { if (0 != remainder.at(i)) { break; } ++shift; } exp_shift_(-shift, res_desc); ret = res.from_v2_(res_desc.desc_, remainder, allocator); } } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "[%s] %% [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::rem_v2_(const ObNumber& other, ObNumber& value, IAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc dividend_desc(d_); Desc divisor_desc(other.d_); LOG_DEBUG("rem_v2_", K(ret), KPC(this), K(other)); int cmp_ret = 0; if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else if (0 >= (cmp_ret = abs_compare(other))) { if (0 == cmp_ret) { res.set_zero(); } else { res.from(*this, allocator); } } else { // promise : dividend > divisor // remove ObCalcVector ObDivArray dividend, divisor, rem; int32_t dividend_move = d_.len_ - 1; int32_t dividend_exp = get_decode_exp(dividend_desc.desc_) - dividend_move; int32_t divisor_move = other.d_.len_ - 1; int32_t divisor_exp = get_decode_exp(divisor_desc.desc_) - divisor_move; dividend_move += std::max(0, dividend_exp - divisor_exp); divisor_move += std::max(0, divisor_exp - dividend_exp); dividend.from(digits_, d_.len_, dividend_move + 1); divisor.from(other.digits_, other.d_.len_, divisor_move + 1); dividend.rem(divisor, rem); if (rem.is_zero()) { res.set_zero(); } else { int64_t sum_exp = get_decode_exp(divisor_desc.desc_); uint32_t sum_digits[OB_REM_BUFFER_SIZE] = {}; rem.get_uint32_digits(sum_digits, OB_REM_BUFFER_SIZE); int32_t offset = 0; int32_t sum_len = rem.len_; while (offset < rem.len_ && sum_digits[offset] == 0) { ++offset; --sum_exp; --sum_len; } if (sum_len > OB_MAX_DECIMAL_DIGIT) { sum_len = OB_MAX_DECIMAL_DIGIT; // normalize_digit_(sum_digits + offset, OB_MAX_DECIMAL_DIGIT); } int32_t end = offset + sum_len - 1; while (sum_digits[end] == 0) { --end; --sum_len; } uint32_t* digit_mem = NULL; Desc sum_desc = exp_rem_(dividend_desc, divisor_desc); if (OB_FAIL(calc_desc_and_check(sum_desc.desc_, sum_exp, (uint8_t)sum_len, sum_desc, is_oracle_mode()))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, (uint32_t*)digit_mem); } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "rem_v2: [%s] %% [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::rem_v3(const ObNumber& other, ObNumber& value, ObIAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; Desc dividend_desc; Desc divisor_desc; dividend_desc.desc_ = d_.desc_; divisor_desc.desc_ = other.d_.desc_; LOG_DEBUG("rem_v3_", K(ret), KPC(this), K(other)); int cmp_ret = 0; if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else if (0 >= (cmp_ret = abs_compare(other))) { if (0 == cmp_ret) { res.set_zero(); } else { res.deep_copy_v3(*this, allocator); } } else { // promise : dividend > divisor // remove ObCalcVector ObDivArray dividend, divisor, rem; int32_t dividend_move = d_.len_ - 1; int32_t dividend_exp = get_decode_exp(dividend_desc.desc_) - dividend_move; int32_t divisor_move = other.d_.len_ - 1; int32_t divisor_exp = get_decode_exp(divisor_desc.desc_) - divisor_move; dividend_move += std::max(0, dividend_exp - divisor_exp); divisor_move += std::max(0, divisor_exp - dividend_exp); dividend.from(digits_, d_.len_, dividend_move + 1); divisor.from(other.digits_, other.d_.len_, divisor_move + 1); dividend.rem(divisor, rem); if (rem.is_zero()) { res.set_zero(); } else { int64_t sum_exp = get_decode_exp(divisor_desc.desc_); uint32_t sum_digits[OB_REM_BUFFER_SIZE] = {}; rem.get_uint32_digits(sum_digits, OB_REM_BUFFER_SIZE); int32_t offset = 0; int32_t sum_len = rem.len_; while (offset < rem.len_ && sum_digits[offset] == 0) { ++offset; --sum_exp; --sum_len; } if (sum_len > OB_MAX_DECIMAL_DIGIT) { sum_len = OB_MAX_DECIMAL_DIGIT; // normalize_digit_(sum_digits + offset, OB_MAX_DECIMAL_DIGIT); } int32_t end = offset + sum_len - 1; while (sum_digits[end] == 0) { --end; --sum_len; } uint32_t* digit_mem = NULL; Desc sum_desc = exp_rem_(dividend_desc, divisor_desc); if (OB_FAIL(calc_desc_and_check(sum_desc.desc_, sum_exp, (uint8_t)sum_len, sum_desc, is_oracle_mode()))) { LOG_WARN("fail to assign desc part", K(ret)); if (OB_DECIMAL_PRECISION_OVERFLOW == ret) { res.set_zero(); ret = OB_SUCCESS; } } else if (OB_ISNULL(digit_mem = (uint32_t*)allocator.alloc(sizeof(uint32_t) * sum_len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc mem", "size", sizeof(uint32_t) * sum_len, K(ret)); } else { MEMCPY(digit_mem, sum_digits + offset, sizeof(uint32_t) * sum_len); res.assign(sum_desc.desc_, (uint32_t*)digit_mem); } } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "rem_v3: [%s] %% [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::sqrt_first_guess_(ObNumber& value, ObIAllocator& allocator) const { // use std::sqrt(double) can get a much better guess and need much fewer loops // in sqrt(). Not doing this for now because we can't do ObNumber <=> double // convertion in ObNumber conveniently. // same as pg's sqrt_var: half highest digit, half exp. int ret = OB_SUCCESS; uint32_t digits[1] = {0}; ObNumber res; if (is_zero()) { // should not happen. sqrt(0) should be handled as a special case without // using sqrt_first_guess_ res.set_zero(); } else if (is_negative()) { LOG_WARN("cannot take sqrt guess of negative arg", KPC(this), K(ret)); ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; } else { Desc guess_desc; guess_desc.desc_ = d_.desc_; // value must be positive here int64_t decoded_exp = guess_desc.exp_ - EXP_ZERO; // handle exp=-1 specially: // 0.36 == (exp=-1, digits=[360000000,]), // -1/2 = 0, 360000000/2 = 180000000, // (exp=0, digits=[180000000,]) == 180000000 is very inappropriate. // guess exp from exp -1 should be -1. // guess of 0.36 will be (exp=-1, digits=[180000000,]) == 0.18 int64_t decoded_new_exp = (decoded_exp == -1) ? -1 : (decoded_exp / 2); guess_desc.exp_ = decoded_new_exp + EXP_ZERO; guess_desc.len_ = 1; guess_desc.cap_ = 1; uint32_t digit = get_digits()[0] / 2; if (0 == digit) { digit = 1; // avoid 0 guess } digits[0] = digit; res.assign(guess_desc.desc_, digits); LOG_DEBUG("sqrt_first_guess_, main path", KPC(this), K(res), K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(res, allocator))) { LOG_WARN("failed: deep_copy res to value", K(ret)); } } _OB_LOG(DEBUG, "sqrt_first_guess_ [%s], ret=%d [%s]", format(), ret, value.format()); return ret; } int ObNumber::sqrt(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; number::ObNumber result; // this check is necessary to avoid "quotient = arg (0) / guess (0)" // OB_DIVISION_BY_ZERO error if (is_zero()) { if (OB_FAIL(result.from(number::ObNumber::get_zero(), allocator))) { LOG_WARN("set result to 0 failed", K(ret)); } } else if (is_negative()) { LOG_WARN("cannot take sqrt of negative arg", KPC(this), K(ret)); ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; } else { const int NUM_ONE_TIME_CLAC = 2; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; // use one_time_allocator for all intermediate allocations and make sure // that the passed-in allocator is only used once for the final result ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); number::ObNumber guess; if (OB_FAIL(sqrt_first_guess_(guess, one_time_allocator))) { LOG_WARN("failed: sqrt_first_guess_", KPC(this), K(ret)); } else { // main loop of Newton's algorithm number::ObNumber quotient; number::ObNumber const_zero_point_five; number::ObNumber new_guess; if (OB_FAIL(const_zero_point_five.from("0.5", one_time_allocator))) { LOG_WARN("fail to initialize const_zero_point_five", K(ret)); } // max number of ObNumber calculations in the following loop. update this // when modifying the following loop const int NUM_MAX_CALC_IN_LOOP = 3; const int LOOP_BUFFER_SIZE = NUM_MAX_CALC_IN_LOOP * MAX_CALC_BYTE_LEN; char loop_buffer_1[LOOP_BUFFER_SIZE]; char loop_buffer_2[LOOP_BUFFER_SIZE]; ObDataBuffer loop_allocator_current(loop_buffer_1, LOOP_BUFFER_SIZE); ObDataBuffer loop_allocator_next(loop_buffer_2, LOOP_BUFFER_SIZE); bool guess_is_answer = false; while (OB_SUCC(ret) && !guess_is_answer) { if (OB_FAIL(div(guess, quotient, loop_allocator_current, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("failed: quotient = this / guess", KPC(this), K(guess), K(ret)); } else if (OB_FAIL(guess.add_v3(quotient, new_guess, loop_allocator_current, true, false))) { // new guess is the average of current guess and quotient LOG_WARN("failed: new_guess = guess + quotient", K(guess), K(quotient), K(ret)); } else if (OB_FAIL(new_guess.mul(const_zero_point_five, new_guess, loop_allocator_current, false))) { // *0.5 is faster than /2 ? LOG_WARN("failed: new_guess *= 0.5", K(new_guess), K(ret)); } else { // why not use "quotient == guess" as end condition: // - arg = 3.16227766016837933199889354443271853372 // - guess = 1.77827941003892280122542119519268484474 // - quotient = 1.77827941003892280122542119519268484473 // - (guess+quotient)/2 = 1.77827941003892280122542119519268484474 = guess // here, guess != quotient, infinite loop. Using guess == new_guess // can avoid this. if (new_guess.is_equal(guess)) { guess_is_answer = true; } else { guess = new_guess; } loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } } if (OB_SUCC(ret)) { if (OB_FAIL(result.from(guess, allocator))) { LOG_WARN("failed: deep copy guess to result", K(ret)); } } } } if (OB_SUCC(ret)) { if (do_rounding && OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } else { value = result; } } _OB_LOG(DEBUG, "sqrt [%s], ret=%d [%s], do_rounding=%d", format(), ret, value.format(), do_rounding); return ret; } int ObNumber::ln(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; number::ObNumber result; // check special value if (is_zero()) { LOG_WARN("cannot get logarithm of zero", KPC(this), K(ret)); ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; } else if (is_negative()) { LOG_WARN("cannot get logarithm of a negative number", KPC(this), K(ret)); ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; // TODO check if this is 1 ? } else { // number of times one_time_allocator is used in this function. update this // when modifying this function const int NUM_ONE_TIME_CLAC = 14; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); // max number of ObNumber calculations in all loops in this function. update // this when modifying while loop in this fun. const int NUM_MAX_CALC_IN_LOOP = 4; const int LOOP_BUFFER_SIZE = NUM_MAX_CALC_IN_LOOP * MAX_CALC_BYTE_LEN; char loop_buffer_1[LOOP_BUFFER_SIZE]; char loop_buffer_2[LOOP_BUFFER_SIZE]; ObDataBuffer loop_allocator_current(loop_buffer_1, LOOP_BUFFER_SIZE); ObDataBuffer loop_allocator_next(loop_buffer_2, LOOP_BUFFER_SIZE); // Reduce *this into range (0.9, 1.1) with repeated sqrt() operations. number::ObNumber const_two; number::ObNumber const_zero_point_nine; number::ObNumber const_one_point_one; number::ObNumber reduced_arg; number::ObNumber reduction_compensation; if (OB_FAIL(const_two.from((int64_t)2, one_time_allocator))) { LOG_WARN("fail to initialize const_two", K(ret)); } else if (OB_FAIL(const_zero_point_nine.from("0.9", one_time_allocator))) { LOG_WARN("fail to initialize const_zero_point_nine", K(ret)); } else if (OB_FAIL(const_one_point_one.from("1.1", one_time_allocator))) { LOG_WARN("fail to initialize const_one_point_one", K(ret)); } else if (OB_FAIL(reduced_arg.from(*this, one_time_allocator))) { LOG_WARN("failed: deep copy this to reduced_arg", KPC(this), K(ret)); } else if (OB_FAIL(reduction_compensation.from(const_two, one_time_allocator))) { // reduction_compensation starts with 2 instead of 1, because the // following taylor series will get 0.5 * ln(reduced_arg), not // ln(reduced_arg) LOG_WARN("failed to initialize reduction_compensation", K(ret)); } else { // note: here this and reduced_arg > 0 while (OB_SUCC(ret) && reduced_arg.compare(const_zero_point_nine) <= 0) { if (OB_FAIL(reduced_arg.sqrt(reduced_arg, loop_allocator_current, false))) { LOG_WARN("sqrt reduced_arg failed", K(reduced_arg), K(ret)); } else if (OB_FAIL( reduction_compensation.mul(const_two, reduction_compensation, loop_allocator_current, false))) { LOG_WARN("reduction_compensation *= 2 failed", K(reduction_compensation), K(ret)); } else { loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } } while (OB_SUCC(ret) && reduced_arg.compare(const_one_point_one) >= 0) { if (OB_FAIL(reduced_arg.sqrt(reduced_arg, loop_allocator_current, false))) { LOG_WARN("sqrt reduced_arg failed", K(reduced_arg), K(ret)); } else if (OB_FAIL( reduction_compensation.mul(const_two, reduction_compensation, loop_allocator_current, false))) { LOG_WARN("reduction_compensation *= 2 failed", K(reduction_compensation), K(ret)); } else { loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } } if (OB_SUCC(ret)) { // loop_calc_allocator will be reuse. move numbers that are used later // to one_time_allocator if (OB_FAIL(reduced_arg.deep_copy_to_allocator_(one_time_allocator))) { LOG_WARN("failed: deep copy reduced_arg to one_time_allocator", K(ret)); } else if (OB_FAIL(reduction_compensation.deep_copy_to_allocator_(one_time_allocator))) { LOG_WARN("failed: deep copy reduction_compensation to one_time_allocator", K(ret)); } } // Taylor series: 0.5 * ln(reduced_arg) = 0.5 * ln((1+z)/(1-z)) = z + z^3/3 + z^5/5 + ..., // where z = (reduced_arg-1)/(reduced_arg+1) if (OB_SUCC(ret)) { // initialize vars number::ObNumber series_number; // z = (reduced_arg-1)/(reduced_arg+1) number::ObNumber z; // z_square = z^2 number::ObNumber z_square; // tmp is only used to store (reduced_arg+1) when calculating z = // (reduced_arg-1)/(reduced_arg+1) number::ObNumber tmp; // term_x_exponent is z^i number::ObNumber term_x_exponent; // term is z^i/i number::ObNumber term; if (OB_FAIL(series_number.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("initialize series_number to 1 failed", K(ret)); } else if (OB_FAIL( reduced_arg.sub_v3(number::ObNumber::get_positive_one(), z, one_time_allocator, true, false))) { LOG_WARN("failed: z=reduced_arg-1", K(reduced_arg), K(z), K(ret)); } else if (OB_FAIL(reduced_arg.add_v3( number::ObNumber::get_positive_one(), tmp, one_time_allocator, true, false))) { LOG_WARN("failed: tmp=reduced_arg+1", K(reduced_arg), K(tmp), K(ret)); } else if (OB_FAIL(z.div(tmp, z, one_time_allocator, OB_MAX_DECIMAL_DIGIT, false))) { // z = (reduced_arg-1)/(reduced_arg+1) now LOG_WARN("failed: z/=tmp, where tmp = reduced_arg+1", K(z), K(tmp), K(ret)); } else if (OB_FAIL(z.mul(z, z_square, one_time_allocator, false))) { LOG_WARN("failed: z_square = z*z", K(z), K(ret)); } else if (OB_FAIL(term_x_exponent.from(z, one_time_allocator))) { LOG_WARN("failed: deep copy z to term_x_exponent", K(ret)); } else if (OB_FAIL(result.from(z, one_time_allocator))) { LOG_WARN("failed: deep copy z to result", K(z), K(ret)); } else { bool term_reachs_zero = false; while (OB_SUCC(ret) && !term_reachs_zero) { // main loop of the Taylor series if (OB_FAIL(series_number.add_v3(const_two, series_number, loop_allocator_current, true, false))) { LOG_WARN("failed: series_number+=2", K(series_number), K(ret)); } else if (OB_FAIL(term_x_exponent.mul(z_square, term_x_exponent, loop_allocator_current, false))) { LOG_WARN("failed: term_x_exponent *= z_square", K(term_x_exponent), K(z_square), K(ret)); } else if (OB_FAIL(term_x_exponent.div( series_number, term, loop_allocator_current, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("failed: term = term_x_exponent / series_number, K(ret)", K(term_x_exponent), K(series_number)); } else { // now we have the term of this loop if (term.is_zero()) { term_reachs_zero = true; } else { if (OB_FAIL(result.add_v3(term, result, loop_allocator_current, true, false))) { LOG_WARN("failed: result += term", K(result), K(term), K(ret)); } } // this iteration is ending. data from last iteration will not // be used any more loop_allocator_next.free(); // should swap internal pointers which point to loop_buffer_1, // loop_buffer_2 std::swap(loop_allocator_current, loop_allocator_next); } } if (OB_SUCC(ret)) { // don't use one_time_allocator here, because result is shallow-copied // to value later. if (OB_FAIL(result.mul(reduction_compensation, result, allocator, false))) { LOG_WARN("failed: result *= reduction_compensation", K(result), K(reduction_compensation), K(ret)); } } } } } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } else { value = result; } } else { value = result; } } _OB_LOG(DEBUG, "ln [%s], ret=%d [%s], do_rounding=%d", format(), ret, value.format(), do_rounding); return ret; } int ObNumber::e_power(ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { LOG_DEBUG("ObExprPower, e_power", K(*this), KPC(this), K(do_rounding)); int ret = OB_SUCCESS; number::ObNumber result; // number of times one_time_allocator is used in this function. update this // when modifying this function const int NUM_ONE_TIME_CLAC = 9; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); // max number of ObNumber calculations in all loops in this function. update // this when modifying while loop in this fun. const int NUM_MAX_CALC_IN_LOOP = 4; const int LOOP_BUFFER_SIZE = NUM_MAX_CALC_IN_LOOP * MAX_CALC_BYTE_LEN; char loop_buffer_1[LOOP_BUFFER_SIZE]; char loop_buffer_2[LOOP_BUFFER_SIZE]; ObDataBuffer loop_allocator_current(loop_buffer_1, LOOP_BUFFER_SIZE); ObDataBuffer loop_allocator_next(loop_buffer_2, LOOP_BUFFER_SIZE); if (is_zero()) { // note: result.set_one() will raise error if not initialized. if (OB_FAIL(result.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("set result to 1 failed", K(ret)); } } else { number::ObNumber exponent_new; if (OB_FAIL(exponent_new.from(*this, one_time_allocator))) { LOG_WARN("deep copy failed", KPC(this), K(ret)); } else { // Reduce exponent_new to the range [-0.01, 0.01] by dividing by 2^n, to // improve the convergence rate of the Taylor series. const char* small_fraction = "0.01"; number::ObNumber small_fraction_number; number::ObNumber const_two; int times_exponent_div_2 = 0; if (OB_FAIL(small_fraction_number.from(small_fraction, one_time_allocator))) { LOG_WARN("initialize small_fraction_number failed", K(ret)); } else if (OB_FAIL(const_two.from((int64_t)2, one_time_allocator))) { LOG_WARN("fail to initialize const_two", K(ret)); } else { while (OB_SUCC(ret) && exponent_new.abs_compare(small_fraction_number) > 0) { if (OB_FAIL(exponent_new.div(const_two, exponent_new, loop_allocator_current, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("exponent_new /= 2 failed", K(exponent_new), K(ret)); } else { times_exponent_div_2++; loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } } if (OB_SUCC(ret)) { if (OB_FAIL(exponent_new.deep_copy_to_allocator_(one_time_allocator))) { LOG_WARN("failed: move exponent_new to one_time_allocator", K(ret)); } } LOG_DEBUG( "reduce exponent_new done", K(exponent_new), K(times_exponent_div_2), K(exponent_new.format()), K(ret)); } if (OB_SUCC(ret)) { // Use the Taylor series: exp(x) = 1 + x + x^2/2! + x^3/3! + ..., here x // is exponent_new number::ObNumber term; // current term in the Taylor series number::ObNumber series_index; if (OB_FAIL(result.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("deep copy positive one failed", K(ret)); } else if (OB_FAIL(term.from(exponent_new, one_time_allocator))) { LOG_WARN("deep copy failed", K(exponent_new), K(ret)); } else if (OB_FAIL(series_index.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("deep copy positive one failed", K(ret)); } else { LOG_DEBUG("begin taylor series", K(result), K(result.format()), K(term), K(term.format()), K(series_index), K(series_index.format()), K(ret)); do { if (OB_FAIL(result.add_v3(term, result, loop_allocator_current, true, false))) { LOG_WARN("failed: result += term", K(ret)); } else if (OB_FAIL(term.mul(exponent_new, term, loop_allocator_current, false))) { LOG_WARN("failed: term *= exponent_new", K(ret)); } else if (OB_FAIL(series_index.add_v3( number::ObNumber::get_positive_one(), series_index, loop_allocator_current, true, false))) { LOG_WARN("failed: series_index += 1", K(ret)); } else if (OB_FAIL(term.div(series_index, term, loop_allocator_current, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("failed: term /= series_index", K(ret)); } else { loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } LOG_DEBUG("in taylor series", K(result), K(result.format()), K(term), K(term.format()), K(series_index), K(series_index.format()), K(ret)); // end condition: term is so small that it is rounded to 0 in div() } while (OB_SUCC(ret) && !term.is_zero()); LOG_DEBUG("after taylor series", K(result), K(result.format()), K(term), K(term.format()), K(series_index), K(series_index.format()), K(ret)); if (OB_SUCC(ret)) { if (OB_FAIL(result.deep_copy_to_allocator_(one_time_allocator))) { LOG_WARN("failed: move result to one_time_allocator", K(ret)); } } LOG_DEBUG("after taylor series, result.deep_copy_to_allocator_", K(result), K(result.format()), K(ret)); // Compensate for the argument range reduction while (OB_SUCC(ret) && times_exponent_div_2-- > 0) { if (OB_FAIL(result.mul(result, result, loop_allocator_current, false))) { LOG_WARN("failed: result *= result", K(ret)); } else { loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } LOG_DEBUG("squaring result", K(result), K(result.format()), K(ret)); } } } } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(result, allocator))) { LOG_WARN("failed: deep copy result to value", K(ret)); } } } _OB_LOG(DEBUG, "e_power [%s], ret=%d [%s]", format(), ret, value.format()); return ret; } int ObNumber::round_remainder(const ObNumber& other, ObNumber& value, ObIAllocator& allocator) const { int ret = OB_SUCCESS; ObNumber res; char buf_alloc[number::ObNumber::MAX_CALC_BYTE_LEN * 2]; ObDataBuffer allocator2(buf_alloc, number::ObNumber::MAX_CALC_BYTE_LEN * 2); if (OB_UNLIKELY(other.is_zero())) { _OB_LOG(ERROR, "[%s] div zero [%s]", to_cstring(*this), to_cstring(other)); ret = OB_DIVISION_BY_ZERO; } else if (is_zero()) { res.set_zero(); } else { /*a.round_remainder(b) = a - b * N; q = a / b; N = q.round_even_number; p = b * N; */ ObNumber q, p; if (OB_FAIL(div(other, q, allocator2))) { LOG_WARN("division failed", K(*this), K(other)); } else if (OB_FAIL(q.round_even_number())) { LOG_WARN("q round_even_number failed", K(*this), K(other), K(q)); } else if (OB_FAIL(other.mul(q, p, allocator2))) { LOG_WARN("b multiply q failed", K(*this), K(other), K(q), K(p)); } else if (OB_FAIL(sub_v3(p, res, allocator))) { LOG_WARN("a subtract (b*q) failed", K(*this), K(other), K(q), K(p)); } } if (OB_SUCC(ret)) { value = res; } _OB_LOG(DEBUG, "round_remainder_,[%s] %% [%s], ret=%d [%s]", this->format(), other.format(), ret, res.format()); return ret; } int ObNumber::power( const int64_t exponent, ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; number::ObNumber result; // max number of times one_time_allocator is used in this function. update // this when modifying this function const int NUM_ONE_TIME_CLAC = 3; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); // check special cases bool done_in_special_cases = true; if (is_zero() && exponent < 0) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("division by zero (base is 0 and exponent is negative)", K(ret), KPC(this), K(exponent)); } else { switch (exponent) { case 0: if (OB_FAIL(result.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("copy one failed", K(ret)); } break; case 1: if (OB_FAIL(result.from(*this, one_time_allocator))) { LOG_WARN("copy base failed", K(ret)); } break; case -1: if (OB_FAIL(number::ObNumber::get_positive_one().div( *this, result, one_time_allocator, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("result=1/base failed", KPC(this), K(ret)); } break; case 2: if (OB_FAIL(mul(*this, result, one_time_allocator, false))) { LOG_WARN("result=base^2 failed", KPC(this), K(ret)); } break; default: if (is_zero()) { if (OB_FAIL(result.from(number::ObNumber::get_zero(), one_time_allocator))) { LOG_WARN("copy zero failed", K(ret)); } } else { done_in_special_cases = false; } break; } } if (OB_SUCC(ret) && not done_in_special_cases) { bool is_exponent_negative = (exponent < 0); int abs_exponent = std::abs(exponent); number::ObNumber base_product; if (OB_FAIL(base_product.from(*this, one_time_allocator))) { LOG_WARN("failed: deep copy this to base_product", K(ret)); } else if ((abs_exponent & 1) != 0) { if (OB_FAIL(result.from(*this, one_time_allocator))) { LOG_WARN("failed: deep copy base to result", K(ret)); } } else { if (OB_FAIL(result.from(number::ObNumber::get_positive_one(), one_time_allocator))) { LOG_WARN("failed: deep copy 1 to result", K(ret)); } } // max number of ObNumber calculations in all loops in this function. update // this when modifying while loop in this fun. const int NUM_MAX_CALC_IN_LOOP = 1; const int LOOP_BUFFER_SIZE = NUM_MAX_CALC_IN_LOOP * MAX_CALC_BYTE_LEN; char loop_buffer_1[LOOP_BUFFER_SIZE]; char loop_buffer_2[LOOP_BUFFER_SIZE]; ObDataBuffer loop_allocator_current(loop_buffer_1, LOOP_BUFFER_SIZE); ObDataBuffer loop_allocator_next(loop_buffer_2, LOOP_BUFFER_SIZE); // in the following while loop, when abs_exponent & 1 == 0, "result *= // base_product" is not calculated and result is still store in the old // allocator. because of this, we can't store it in loop_allocator_current // without deep-copy. And to avoid deep-copying result in each loop where // abs_exponent & 1 == 0, we use separated allocators for result. const int RESULT_BUFFER_SIZE = MAX_CALC_BYTE_LEN; char result_buffer_1[RESULT_BUFFER_SIZE]; char result_buffer_2[RESULT_BUFFER_SIZE]; ObDataBuffer result_allocator_current(result_buffer_1, RESULT_BUFFER_SIZE); ObDataBuffer result_allocator_next(result_buffer_2, RESULT_BUFFER_SIZE); while (OB_SUCC(ret) and (abs_exponent >>= 1) > 0) { if (OB_FAIL(base_product.mul(base_product, base_product, loop_allocator_current, false))) { LOG_WARN("failed: square base_product", K(ret)); } else if (abs_exponent & 1) { if (OB_FAIL(result.mul(base_product, result, result_allocator_current, false))) { LOG_WARN("failed: result *= base_product", K(ret)); } else { result_allocator_next.free(); std::swap(result_allocator_current, result_allocator_next); } } // TODO check overflow(positive exponent)/underflow(negative exponent) if (OB_SUCC(ret)) { loop_allocator_next.free(); std::swap(loop_allocator_current, loop_allocator_next); } } if (OB_SUCC(ret)) { if (is_exponent_negative) { if (OB_FAIL(number::ObNumber::get_positive_one().div( result, result, one_time_allocator, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("failed: result = 1 / result", K(ret)); } } else if (OB_FAIL(result.deep_copy_to_allocator_(one_time_allocator))) { LOG_WARN("failed: move result to one_time_allocator", K(ret)); } } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(result, allocator))) { LOG_WARN("failed: deep copy result to value", K(ret)); } } } _OB_LOG(DEBUG, "power (int exponent) ( [%s], [%ld] ), do_rounding=%d, ret=%d [%s]", format(), exponent, do_rounding, ret, result.format()); return ret; } int ObNumber::power( const ObNumber& exponent, ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { int ret = OB_SUCCESS; number::ObNumber result; LOG_DEBUG("power() start", KPC(this), K(exponent), K(do_rounding)); // max number of times one_time_allocator is used in this function. update // this when modifying this function const int NUM_ONE_TIME_CLAC = 3; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); // if exponent is an integer and can store in an int64_t, use power(int) int64_t exponent_int = 0; // TODO which method to use? is_integer(), is_valid_int(), ... if (exponent.is_integer() && OB_SUCCESS == exponent.cast_to_int64(exponent_int)) { LOG_DEBUG("use power(int)", KPC(this), K(exponent_int)); if (OB_FAIL(power(exponent_int, result, one_time_allocator, false))) { LOG_WARN("failed: power(int)", KPC(this), K(exponent_int), K(result), K(ret)); } } else if (is_zero()) { if (exponent.is_negative()) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("calc power failed, exp is negative and base is zero", K(ret)); } else if (exponent.is_zero()) { // 0 ^ 0 = 1 is handled in power(int), not here. ret = OB_ERR_UNEXPECTED; LOG_WARN("cannot reach here", K(ret)); } else { if (OB_FAIL(result.from(number::ObNumber::get_zero(), one_time_allocator))) { LOG_WARN("failed: copy zero to result", K(ret)); } } // TODO check if base is 1 ? } else { // the main path: result = e^(ln(base)*exponent) if (OB_FAIL(ln(result, one_time_allocator, false))) { LOG_WARN("failed: result = ln(base)", K(ret)); } else if (OB_FAIL(result.mul(exponent, result, one_time_allocator, false))) { LOG_WARN("failed: result *= exponent", K(ret)); } else if (OB_FAIL(result.e_power(result, one_time_allocator, false))) { LOG_WARN("failed: result = e^result", K(ret)); } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(result, allocator))) { LOG_WARN("failed: deep copy result to value", K(ret)); } } } _OB_LOG(DEBUG, "power ( [%s], [%s] ), do_rounding=%d, ret=%d [%s]", format(), exponent.format(), do_rounding, ret, result.format()); return ret; } int ObNumber::log(const ObNumber& base, ObNumber& value, ObIAllocator& allocator, const bool do_rounding /*true*/) const { // log_b(x) = ln(x)/ln(b) int ret = OB_SUCCESS; number::ObNumber result; LOG_DEBUG("log() start", KPC(this), K(base), K(do_rounding)); // max number of times one_time_allocator is used in this function. update // this when modifying this function const int NUM_ONE_TIME_CLAC = 3; const int ONE_TIME_BUFFER_SIZE = NUM_ONE_TIME_CLAC * MAX_CALC_BYTE_LEN; char one_time_buffer[ONE_TIME_BUFFER_SIZE]; ObDataBuffer one_time_allocator(one_time_buffer, ONE_TIME_BUFFER_SIZE); // check arguments if (base.is_zero() || base.is_negative()) { ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; LOG_WARN("the base of logarithm has to be positive", K(base), K(ret)); } else if (base.compare(number::ObNumber::get_positive_one()) == 0) { ret = OB_ERR_ARGUMENT_OUT_OF_RANGE; LOG_WARN("the base of logarithm can't be 1", K(base), K(ret)); // log_b(x), the validity of x will be check in ln(x) } else { number::ObNumber ln_x; number::ObNumber ln_base; if (OB_FAIL(ln(ln_x, one_time_allocator, false))) { LOG_WARN("failed: ln_x = ln(this)", KPC(this), K(ret)); } else if (OB_FAIL(base.ln(ln_base, one_time_allocator, false))) { LOG_WARN("failed: ln_base = ln(base)", K(ret)); } else if (OB_FAIL(ln_x.div(ln_base, result, one_time_allocator, OB_MAX_DECIMAL_DIGIT, false))) { LOG_WARN("failed: result = ln_x / ln_base", K(ln_x), K(ln_base), K(ret)); } } if (OB_SUCC(ret)) { if (do_rounding) { if (OB_FAIL(result.round_scale_v3_(is_oracle_mode() ? MAX_SCALE : FLOATING_SCALE, true, false))) { LOG_WARN("result.round_scale_v3_() fail", K(ret), K(result)); } } if (OB_SUCC(ret)) { if (OB_FAIL(value.from(result, allocator))) { LOG_WARN("failed: deep copy result to value", K(ret)); } } } _OB_LOG(DEBUG, "log ( [%s], [%s] ), do_rounding=%d, ret=%d [%s]", format(), base.format(), do_rounding, ret, result.format()); return ret; } // int64_t range [-9,223,372,036,854,775,808, 9,223,372,036,854,775,807] bool ObNumber::is_int64() const { bool b_ret = true; if (is_zero()) { b_ret = true; } else { const int32_t exp = get_decode_exp(d_); if (!is_integer(exp)) { // exponential must great than or equal to 0 b_ret = false; } else if (exp > 2) { // exponential must less than or equal to 2 b_ret = false; } else if (2 == exp) { const uint32_t MAX_HIGH_NUM = 9; const uint32_t MAX_MID_NUM = 223372036; const uint32_t MAX_POSITIVE_LOW_NUM = 854775807; const uint32_t MAX_NEGATIVE_LOW_NUM = 854775808; // no need to check digits_ max length because it is already guaranteed in is_integer(exp) // that: exp + 1 >= d_.len_. So here max length of digits_ is 3. if (digits_[0] > MAX_HIGH_NUM) { b_ret = false; } else if (d_.len_ >= 2 && MAX_HIGH_NUM == digits_[0] && digits_[1] > MAX_MID_NUM) { b_ret = false; } else if (d_.len_ >= 3 && MAX_HIGH_NUM == digits_[0] && MAX_MID_NUM == digits_[1]) { if (is_negative() && digits_[2] > MAX_NEGATIVE_LOW_NUM) { b_ret = false; } else if (!is_negative() && digits_[2] > MAX_POSITIVE_LOW_NUM) { b_ret = false; } else { b_ret = true; } } else { b_ret = true; } } else { // exponential is 0 or 1 b_ret = true; } } return b_ret; } int ObNumber::cast_to_int64(int64_t& value) const { int ret = OB_SUCCESS; bool is_valid_integer = true; uint64_t tmp_value = 0; if (is_zero()) { value = 0; } else if (!is_int64()) { is_valid_integer = false; } else { const int32_t expr_value = get_decode_exp(d_); switch (expr_value) { case 0: { if (1 == d_.len_) { tmp_value = digits_[0]; } break; } case 1: { if (1 == d_.len_) { tmp_value = digits_[0] * BASE; } else if (2 == d_.len_) { tmp_value = digits_[0] * BASE + digits_[1]; } break; } case 2: { switch (d_.len_) { case 1: { const uint64_t tmp_v1 = digits_[0] * BASE; tmp_value = tmp_v1 * BASE; break; } case 2: { const uint64_t tmp_v1 = digits_[0] * BASE; const uint64_t tmp_v2 = tmp_v1 * BASE; const uint64_t tmp_v3 = digits_[1] * BASE; tmp_value = tmp_v2 + tmp_v3; break; } case 3: { const uint64_t tmp_v1 = digits_[0] * BASE; const uint64_t tmp_v2 = tmp_v1 * BASE; const uint64_t tmp_v3 = digits_[1] * BASE; tmp_value = tmp_v2 + tmp_v3 + digits_[2]; break; } default: { is_valid_integer = false; break; } } break; } default: { is_valid_integer = false; break; } } if (is_valid_integer) { value = is_negative() ? 0 - tmp_value : tmp_value; LOG_DEBUG("finish cast_to_int64", K(tmp_value), K(is_valid_integer), KPC(this), K(value)); } } if (OB_UNLIKELY(!is_valid_integer)) { ret = OB_INTEGER_PRECISION_OVERFLOW; LOG_DEBUG("this is not valid integer number", KPC(this), K(ret)); } return ret; } /** * check whether a sci format string has a valid exponent part * valid : 1.8E-1/1.8E1 invalid : 1.8E, 1.8Ea, 1.8E-a * @param str string need to parse * @param length length of str * @param e_pos index of 'E' */ bool ObNumber::is_valid_sci_tail_(const char *str, const int64_t length, const int64_t e_pos) { bool res = false; if (e_pos == length - 1) { //like 1.8e, false } else if (e_pos < length - 1) { if ('+' == str[e_pos + 1] || '-' == str[e_pos + 1]) { if (e_pos < length - 2 && str[e_pos + 2] >= '0' && str[e_pos + 2] <= '9') { res = true; } else { //like 1.8e+, false } } else if (str[e_pos + 1] >= '0' && str[e_pos + 1] <= '9') { res = true; } else { //like 1.8ea, false } } return res; } void ObNumber::set_one() { if (OB_ISNULL(digits_)) { _OB_LOG(ERROR, "number digit ptr is null where set to one!"); right_to_die_or_duty_to_live(); } else { d_.len_ = 1; digits_[0] = 1; d_.se_ = (POSITIVE == d_.sign_ ? 0xc0 : 0x40); } } //////////////////////////////////////////////////////////////////////////////////////////////////// ObIntegerBuilder::ObIntegerBuilder() : exp_(0), digit_pos_(ObNumber::MAX_CALC_LEN - 1), digit_idx_(0) {} ObIntegerBuilder::~ObIntegerBuilder() {} int ObIntegerBuilder::push(const uint8_t d, const bool reduce_zero) { int ret = OB_SUCCESS; if (OB_UNLIKELY(get_length() > ObNumber::MAX_CALC_LEN)) { ret = OB_NUMERIC_OVERFLOW; } else { if (0 == digit_idx_) { // Init current digit on first use digits_[digit_pos_] = 0; } // 1234 // push [4]: 4 = 4 // push [3]: 3*10 + 4= 34 // push [2]: 2*100 + 34 = 234 // push [1]: 1*1000 + 234 = 1234 static const uint32_t POWS[ObNumber::DIGIT_LEN] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; digits_[digit_pos_] += d * POWS[digit_idx_++]; if (ObNumber::DIGIT_LEN <= digit_idx_) { if (!reduce_zero || 0 != digits_[ObNumber::MAX_CALC_LEN - 1]) { --digit_pos_; } digit_idx_ = 0; ++exp_; } } return ret; } int ObIntegerBuilder::push_digit(const uint32_t d, const bool reduce_zero) { int ret = OB_SUCCESS; if (OB_ISNULL(digits_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(ret)); } else if (OB_UNLIKELY(get_length() > ObNumber::MAX_CALC_LEN)) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("numeric_overflow", K(digit_idx_), K(digit_pos_), K(ret)); } else { digits_[digit_pos_] = d; if (!reduce_zero || 0 != digits_[ObNumber::MAX_CALC_LEN - 1]) { --digit_pos_; } ++exp_; } return ret; } int64_t ObIntegerBuilder::get_exp() const { return (0 == digit_idx_) ? (exp_ - 1) : exp_; } int64_t ObIntegerBuilder::get_length() const { return (0 == digit_idx_) ? (ObNumber::MAX_CALC_LEN - digit_pos_ - 1) : (ObNumber::MAX_CALC_LEN - digit_pos_); } const uint32_t* ObIntegerBuilder::get_digits() const { return (0 == get_length()) ? NULL : &digits_[ObNumber::MAX_CALC_LEN - get_length()]; } void ObIntegerBuilder::reset() { exp_ = 0; digit_pos_ = ObNumber::MAX_CALC_LEN - 1; digit_idx_ = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// ObDecimalBuilder::ObDecimalBuilder() : exp_(-1), digit_pos_(0), digit_idx_(0) {} ObDecimalBuilder::~ObDecimalBuilder() {} int ObDecimalBuilder::push(const uint8_t d, const bool reduce_zero) { int ret = OB_SUCCESS; if (OB_UNLIKELY(get_length() >= ObNumber::MAX_CALC_LEN)) { ret = OB_NUMERIC_OVERFLOW; } else { if (0 == digit_idx_) { // Init current digit on first use digits_[digit_pos_] = 0; } // 0.1234 // push [1]: 0 + 1*100000000 = 100000000 // push [2]: 100000000 + 2*10000000 = 120000000 // push [3]: 120000000 + 3*1000000 = 123000000 // push [4]: 123000000 + 4*100000 = 123400000 static const uint32_t POWS[ObNumber::DIGIT_LEN] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; digits_[digit_pos_] += d * POWS[digit_idx_++]; if (ObNumber::DIGIT_LEN <= digit_idx_) { if (!reduce_zero || 0 != digits_[0]) { digit_pos_ += 1; } else { --exp_; } digit_idx_ = 0; } } return ret; } int ObDecimalBuilder::push_digit(const uint32_t d, const bool reduce_zero) { int ret = OB_SUCCESS; if (OB_UNLIKELY(get_length() >= ObNumber::MAX_CALC_LEN)) { ret = OB_NUMERIC_OVERFLOW; LOG_WARN("numeric_overflow", K(digit_idx_), K(digit_pos_), K(ret)); } else { digits_[digit_pos_] = d; if (!reduce_zero || 0 != digits_[0]) { ++digit_pos_; } else { --exp_; } } return ret; } int64_t ObDecimalBuilder::get_exp() const { return exp_; } int64_t ObDecimalBuilder::get_length() const { return (0 == digit_idx_) ? digit_pos_ : (digit_pos_ + 1); } const uint32_t* ObDecimalBuilder::get_digits() const { return (0 == get_length()) ? NULL : &digits_[0]; } void ObDecimalBuilder::reset() { exp_ = -1; digit_pos_ = 0; digit_idx_ = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// void ObNumberBuilder::reset() { number_.set_zero(); } int ObNumberBuilder::build( const char* str, int64_t length, int& warning, ObNumberFmtModel* fmt, int16_t* precision, int16_t* scale) { int ret = OB_SUCCESS; reset(); bool negative = false; int64_t integer_start = -1; int64_t integer_end = -1; int64_t decimal_start = -1; bool integer_zero = false; bool decimal_zero = false; char new_str[ObNumber::MAX_TOTAL_SCALE]; int64_t comma_cnt = 0; if (OB_ISNULL(number_.get_digits())) { ret = OB_ERR_UNEXPECTED; LIB_LOG(WARN, "digits_ should not be null when this func is invoked", K(ret)); } else { if (OB_ISNULL(fmt)) { if (OB_FAIL(find_point_( str, length, integer_start, integer_end, decimal_start, negative, integer_zero, decimal_zero, warning))) { LIB_LOG(WARN, "lookup fail", K(ret), K(length), "str", ObString(length, str)); } } else { if (OB_FAIL(find_point_(str, fmt, &new_str[0], length, integer_start, integer_end, decimal_start, negative, integer_zero, decimal_zero, comma_cnt))) { LIB_LOG(WARN, "lookup fail ", K(ret), "str", ObString(length, str), K(fmt->fmt_str_), K(fmt->has_b_), K(fmt->has_currency_), K(fmt->has_d_), K(fmt->has_sign_)); } else { LIB_LOG(DEBUG, "lookup success with fmt", K(ret), K(fmt->fmt_str_), K(fmt->has_b_), K(fmt->has_currency_), K(fmt->has_d_), K(fmt->has_sign_), K(new_str), K(length), K(integer_start), K(integer_end), K(decimal_start), K(negative), K(integer_zero), K(decimal_zero)); str = &new_str[0]; } } } if (OB_SUCC(ret)) { if (OB_FAIL(build_integer_(str, integer_start, integer_end, decimal_zero, fmt))) { LIB_LOG(WARN, "build integer fail", K(ret), K(length), "str", ObString(length, str), K(integer_start), K(integer_end), K(decimal_zero)); } else if (OB_FAIL(build_decimal_(str, length, decimal_start, integer_zero))) { LIB_LOG(WARN, "build decimal fail", K(ret), K(length), "str", ObString(length, str), K(decimal_start), K(integer_zero)); } else if (OB_UNLIKELY(ib_.get_length() < 0 || db_.get_length() < 0)) { ret = OB_ERR_UNEXPECTED; LIB_LOG(ERROR, "unexpected integer length or decimal length. ", K(ret), K(ib_.get_length()), K(db_.get_length())); } else if (OB_UNLIKELY(ib_.get_length() + db_.get_length() > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; LIB_LOG(WARN, "out of range, integer length, decimal length", K(ret), K(ib_.get_length()), K(db_.get_length())); } else { if (!negative) { number_.d_.sign_ = ObNumber::POSITIVE; } else { number_.d_.sign_ = ObNumber::NEGATIVE; } if (0 != ib_.get_length()) { number_.d_.exp_ = 0x7f & (uint8_t)(ObNumber::EXP_ZERO + ib_.get_exp()); } else { number_.d_.exp_ = 0x7f & (uint8_t)(ObNumber::EXP_ZERO + db_.get_exp()); } number_.d_.len_ = (uint8_t)(ib_.get_length() + db_.get_length()); if (negative) { number_.d_.exp_ = (0x7f & ~number_.d_.exp_); ++number_.d_.exp_; } if (NULL != number_.get_digits() && 0 < ib_.get_length()) { MEMCPY(number_.get_digits(), ib_.get_digits(), ib_.get_length() * ITEM_SIZE(number_.get_digits())); } if (NULL != number_.get_digits() && 0 < db_.get_length()) { MEMCPY(&number_.get_digits()[ib_.get_length()], db_.get_digits(), db_.get_length() * ITEM_SIZE(number_.get_digits())); } if (NULL != precision && NULL != scale) { *scale = static_cast((length - decimal_start == -1) ? 0 : (length - decimal_start)); if (*scale > ObNumber::FLOATING_SCALE) { *scale = ObNumber::FLOATING_SCALE; } *precision = static_cast(integer_end - integer_start + 1 - comma_cnt + *scale); } ret = number_.normalize_(number_.get_digits(), number_.d_.len_); } } return ret; } int ObNumberBuilder::build_v2( const char* str, int64_t length, int& warning, ObNumberFmtModel* fmt, int16_t* precision, int16_t* scale) { int ret = OB_SUCCESS; reset(); bool negative = false; int64_t integer_start = -1; int64_t integer_end = -1; int64_t decimal_start = -1; bool integer_zero = false; bool decimal_zero = false; char new_str[ObNumber::MAX_TOTAL_SCALE]; int64_t comma_cnt = 0; if (OB_ISNULL(number_.get_digits())) { ret = OB_ERR_UNEXPECTED; LIB_LOG(WARN, "digits_ should not be null when this func is invoked", K(ret)); } else { if (OB_ISNULL(fmt)) { if (OB_FAIL(lib::is_oracle_mode() ? find_point_v2_(str, length, integer_start, integer_end, decimal_start, negative, integer_zero, decimal_zero, warning) : find_point_(str, length, integer_start, integer_end, decimal_start, negative, integer_zero, decimal_zero, warning))) { LIB_LOG(WARN, "lookup fail", K(ret), K(length), "str", ObString(length, str), "is_oracle_mode", lib::is_oracle_mode()); } } else { // used for to_number(format) if (OB_FAIL(find_point_(str, fmt, &new_str[0], length, integer_start, integer_end, decimal_start, negative, integer_zero, decimal_zero, comma_cnt))) { LIB_LOG(WARN, "lookup fail ", K(ret), "str", ObString(length, str), K(fmt->fmt_str_), K(fmt->has_b_), K(fmt->has_currency_), K(fmt->has_d_), K(fmt->has_sign_), K(fmt->has_x_)); } else { LIB_LOG(DEBUG, "lookup success with fmt", K(ret), K(fmt->fmt_str_), K(fmt->has_b_), K(fmt->has_currency_), K(fmt->has_d_), K(fmt->has_sign_), K(fmt->has_x_), K(new_str), K(length), K(integer_start), K(integer_end), K(decimal_start), K(negative), K(integer_zero), K(decimal_zero)); str = &new_str[0]; } } } if (OB_SUCC(ret)) { if (OB_FAIL(build_integer_v2_(str, integer_start, integer_end, decimal_zero, integer_zero, warning, fmt))) { LIB_LOG(WARN, "build integer fail", K(ret), K(length), "str", ObString(length, str), K(integer_start), K(integer_end), K(decimal_zero), K(integer_zero)); } else if (OB_FAIL(build_decimal_v2_(str, length, decimal_start, integer_zero, decimal_zero, warning))) { LIB_LOG(WARN, "build decimal fail", K(ret), K(length), "str", ObString(length, str), K(decimal_start), K(integer_zero), K(decimal_zero)); } else if (OB_UNLIKELY(ib_.get_length() < 0) || OB_UNLIKELY(db_.get_length() < 0)) { ret = OB_ERR_UNEXPECTED; LIB_LOG(ERROR, "unexpected integer length or decimal length. ", K(ret), K(ib_.get_length()), K(db_.get_length())); } else if (OB_UNLIKELY(ib_.get_length() + db_.get_length() > ObNumber::MAX_CALC_LEN)) { ret = OB_ERROR_OUT_OF_RANGE; LIB_LOG(WARN, "out of range, integer length, decimal length", K(ret), K(ib_.get_length()), K(db_.get_length())); } else { number_.d_.sign_ = 0x01 & (negative ? ObNumber::NEGATIVE : ObNumber::POSITIVE); number_.d_.len_ = (uint8_t)(ib_.get_length() + db_.get_length()); number_.d_.exp_ = 0x7f & (uint8_t)(ObNumber::EXP_ZERO + (ib_.get_length() != 0 ? ib_.get_exp() : db_.get_exp())); if (negative) { number_.d_.exp_ = (0x7f & ~number_.d_.exp_); ++number_.d_.exp_; } MEMCPY(number_.get_digits(), ib_.get_digits(), ib_.get_length() * ITEM_SIZE(number_.get_digits())); MEMCPY(number_.get_digits() + ib_.get_length(), db_.get_digits(), db_.get_length() * ITEM_SIZE(number_.get_digits())); if (NULL != precision && NULL != scale) { *scale = static_cast((length - decimal_start == -1) ? 0 : (length - decimal_start)); if (*scale > ObNumber::FLOATING_SCALE) { *scale = ObNumber::FLOATING_SCALE; } *precision = static_cast(integer_end - integer_start + 1 - comma_cnt + *scale); } ret = number_.normalize_v3_(false); } } LIB_LOG(DEBUG, "succ to build_v2", K(number_), K(ret), K(warning)); return ret; } int ObNumberBuilder::build_integer_( const char* str, const int64_t integer_start, const int64_t integer_end, const bool reduce_zero) { int ret = OB_SUCCESS; ib_.reset(); int64_t skiped_zero_counter = 0; if (OB_UNLIKELY(integer_start <= integer_end && NULL == str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (integer_start >= 0 && integer_end >= 0) { for (int64_t i = integer_end; i >= integer_start; --i) { char c = str[i]; if ('0' == c) { ++skiped_zero_counter; continue; } else { for (int64_t j = 0; j < skiped_zero_counter; ++j) { if (OB_FAIL(ib_.push(0, reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(j)); break; } } if (OB_FAIL(ret)) { break; } skiped_zero_counter = 0; } if (OB_FAIL(ib_.push((uint8_t)(c - '0'), reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(c)); break; } } } else { /* Do nothing */ } return ret; } int ObNumberBuilder::build_integer_v2_(const char* str, const int64_t integer_start, const int64_t integer_end, const bool reduce_zero, const bool integer_zero, int& warning) { int ret = OB_SUCCESS; static const uint32_t POWS[ObNumber::DIGIT_LEN] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; if (integer_zero) { ib_.reset(); } else if (OB_UNLIKELY(integer_start <= integer_end) && OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(integer_start), K(integer_end), K(ret)); } else if (OB_LIKELY(integer_start >= 0) && OB_LIKELY(integer_end >= 0)) { uint32_t tmp = 0; int64_t idx = 0; int64_t non_zero_start = integer_start; while (non_zero_start <= integer_end && str[non_zero_start] == '0') { ++non_zero_start; } for (int64_t i = integer_end; OB_SUCC(ret) && i >= non_zero_start; --i) { int32_t tmp_value = str[i] - '0'; if (OB_UNLIKELY(tmp_value < 0) || OB_UNLIKELY(tmp_value > 9)) { warning = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error: got ", K(ret), K(warning), K(str[i]), K(tmp_value)); } else { tmp += static_cast(POWS[idx++] * tmp_value); if (idx >= ObNumber::DIGIT_LEN || i == non_zero_start) { if (OB_FAIL(ib_.push_digit(tmp, reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(i)); break; } tmp = 0; idx = 0; } } } } return ret; } int ObNumberBuilder::hex_to_num_(char c, int32_t& val) const { int ret = OB_SUCCESS; if (c >= '0' && c <= '9') { val = c - '0'; } else if (c >= 'a' && c <= 'z') { val = c - 'a' + 10; } else if (c >= 'A' && c <= 'Z') { val = c - 'A' + 10; } else { ret = OB_ERR_UNEXPECTED; LOG_ERROR("bad hexadecimal character", K(ret)); } return ret; } int ObNumberBuilder::multiply_(int32_t multiplier, char* str, int32_t& len) const { int ret = OB_SUCCESS; if (OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (len >= ObNumber::MAX_TOTAL_SCALE) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("str exceeds the max length"); } else { int32_t carry = 0; int32_t i = len; int32_t tmp_str_idx = 0; char tmp_str[ObNumber::MAX_TOTAL_SCALE] = {0}; while (OB_SUCC(ret) && --i >= 0) { int val = 0; if (OB_FAIL(hex_to_num_(str[i], val))) { LOG_ERROR("failed to hex_to_num_", K(ret)); } else { val = val * multiplier + carry; carry = std::floor(val / 10); tmp_str[tmp_str_idx++] = (val % 10) + '0'; } } if (OB_SUCC(ret)) { while (carry > 0) { tmp_str[tmp_str_idx++] = (carry % 10) + '0'; carry = std::floor(carry / 10); } // reverse tmp str len = 0; i = --tmp_str_idx; for (; i >= 0; --i) { str[len++] = tmp_str[i]; } } } return ret; } int ObNumberBuilder::add_hex_str_(const char* str1, int32_t str1_len, char* str2, int32_t& str2_len) const { int ret = OB_SUCCESS; if (OB_ISNULL(str1)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (str1_len >= ObNumber::MAX_TOTAL_SCALE) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("str exceeds the max length"); } else { int32_t carry = 0; int32_t i = 0; int val = 0; int32_t tmp_str_idx = 0; char tmp_str[ObNumber::MAX_TOTAL_SCALE] = {0}; while (OB_SUCC(ret) && i < str1_len && i < str2_len) { int32_t val1 = 0; int32_t val2 = 0; if (OB_FAIL(hex_to_num_(str1[str1_len - i - 1], val1)) || OB_FAIL(hex_to_num_(str2[str2_len - i - 1], val2))) { LOG_ERROR("failed to hex_to_num_", K(ret)); } else { val = val1 + val2 + carry; carry = std::floor(val / 10); tmp_str[tmp_str_idx++] = (val % 10) + '0'; i++; } } while (OB_SUCC(ret) && i < str1_len) { int32_t val1 = 0; if (OB_FAIL(hex_to_num_(str1[str1_len - i - 1], val1))) { LOG_ERROR("failed to hex_to_num_", K(ret)); } else { val = val1 + carry; carry = std::floor(val / 10); tmp_str[tmp_str_idx++] = (val % 10) + '0'; i++; } } while (OB_SUCC(ret) && i < str2_len) { int32_t val2 = 0; if (OB_FAIL(hex_to_num_(str2[str2_len - i - 1], val2))) { LOG_ERROR("failed to hex_to_num_", K(ret)); } else { val = val2 + carry; carry = std::floor(val / 10); tmp_str[tmp_str_idx++] = (val % 10) + '0'; i++; } } if (OB_SUCC(ret)) { while (carry > 0) { tmp_str[tmp_str_idx++] = (carry % 10) + '0'; carry = std::floor(carry / 10); } // reverse tmp str str2_len = 0; i = --tmp_str_idx; for (; i >= 0; --i) { str2[str2_len++] = tmp_str[i]; } } } return ret; } int ObNumberBuilder::hex_to_dec_(const char* hex_str, int32_t hex_len, char* dec_str, int32_t& dec_len) const { int ret = OB_SUCCESS; int32_t i = 0; char str[ObNumber::MAX_TOTAL_SCALE] = {0}; while (OB_SUCC(ret) && i < hex_len) { int32_t j = i; str[0] = hex_str[hex_len - 1 - i]; int32_t str_len = 1; while (OB_SUCC(ret) && j--) { if (OB_FAIL(multiply_(16, str, str_len))) { LOG_WARN("failed to multiply_", K(ret)); } } if (OB_SUCC(ret)) { ret = add_hex_str_(str, str_len, dec_str, dec_len); i++; } } return ret; } int ObNumberBuilder::build_hex_integer_(const char* str, const int64_t integer_start, const int64_t integer_end, const bool reduce_zero, ObNumberFmtModel* fmt) { int ret = OB_SUCCESS; if (OB_ISNULL(fmt)) { ret = build_integer_(str, integer_start, integer_end, reduce_zero); } else { // the maximum length of Oracle to_number(123, 'xxx') format is 63 const int32_t MAX_FORMAT_LEN = 64; int64_t c_p = fmt->fmt_len_ - 1; ib_.reset(); int64_t skiped_zero_counter = 0; if (OB_UNLIKELY(c_p >= MAX_FORMAT_LEN)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the format exceeds the max length"); } else if (OB_UNLIKELY(integer_start <= integer_end && NULL == str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (integer_start >= 0 && integer_end >= 0) { int32_t new_len = 0; bool digit_appeared = false; int64_t i = integer_start; int err = 0; // though err != 0 , we still use dec as the valid argument of next step. int64_t dec = 0; char hex_str[ObNumber::MAX_TOTAL_SCALE] = {0}; char dec_str[ObNumber::MAX_TOTAL_SCALE] = {0}; for (; i <= integer_end && c_p >= 0; ++i) { char c = str[i]; switch (c) { case ',': /* do nothing */ break; case '0': if (!digit_appeared) { /* do nothing */ } else { hex_str[new_len++] = c; --c_p; } break; case 'a' ... 'f': case 'A' ... 'F': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': digit_appeared = true; hex_str[new_len++] = c; --c_p; break; default: ret = OB_INVALID_NUMERIC; LOG_WARN("ObNumber got str error: got ", K(ret), K(c)); break; } } if (i < integer_end) { ret = OB_INVALID_NUMERIC; LOG_WARN("integer part is longer than fmt str", K(ret), K(i), K(c_p)); } int32_t dec_len = 0; if (OB_FAIL(hex_to_dec_(hex_str, new_len, dec_str, dec_len))) { LOG_WARN("failed to hex_to_dec", K(ret)); } i = dec_len - 1; for (; i >= 0; --i) { char c = dec_str[i]; if (OB_FAIL(ib_.push((uint8_t)(c - '0'), reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(c)); break; } } } else { /* Do nothing */ } } return ret; } int ObNumberBuilder::build_integer_(const char* str, const int64_t integer_start, const int64_t integer_end, const bool reduce_zero, ObNumberFmtModel* fmt) { int ret = OB_SUCCESS; if (OB_ISNULL(fmt)) { ret = build_integer_(str, integer_start, integer_end, reduce_zero); } else { ib_.reset(); int64_t skiped_zero_counter = 0; if (OB_UNLIKELY(integer_start <= integer_end && NULL == str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (integer_start >= 0 && integer_end >= 0) { int64_t c_p = fmt->fmt_len_ - 1; char* fmt_str = fmt->fmt_str_; bool got_comma_in_fmt = false; bool pass_first_comma = false; if (fmt->dc_position_ >= 0) { c_p = fmt->dc_position_ - 1; } // comma: 4 32 1 4 32 // to_number('76,669,,83,5', '999,999,,999')=>76669835 // digit: 81 654 32 1 987 654 321 // check from right to left, before comma appears at fmt str for the first time, all commas in number_str can be // ignored after the first appearance, commas in number_str must match with the fmt str so as the upper case, // comma 1 can be ignored, comma 2\3\4 are match with fmt str int64_t i = integer_end; for (; i >= integer_start && c_p >= 0; --i) { char c = str[i]; if ('0' == c) { ++skiped_zero_counter; --c_p; if (got_comma_in_fmt && !pass_first_comma) { pass_first_comma = true; } continue; } else if (',' == c) { if (pass_first_comma && ',' != fmt_str[c_p]) { ret = OB_INVALID_NUMERIC; LOG_WARN("comma(s) not match", K(ret), K(c_p), K(i), K(fmt_str[c_p])); break; } else if (',' == fmt_str[c_p]) { got_comma_in_fmt = true; --c_p; } // LOG_DEBUG("ignore comma", K(ret), K(c_p), K(i), K(fmt_str[c_p])); continue; } else if (',' == fmt_str[c_p]) { ret = OB_INVALID_NUMERIC; LOG_WARN("got error during build integer", K(ret), K(i), K(fmt_str[c_p]), K(c_p)); break; } else { if (got_comma_in_fmt && !pass_first_comma) { pass_first_comma = true; } for (int64_t j = 0; j < skiped_zero_counter; ++j) { if (OB_FAIL(ib_.push(0, reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(j)); break; } } if (OB_FAIL(ret)) { break; } skiped_zero_counter = 0; --c_p; } if (OB_FAIL(ib_.push((uint8_t)(c - '0'), reduce_zero))) { LOG_WARN("push to integer builder fail", K(ret), K(c)); break; } } /* fmt 0: there must be a digit that matches with the 0 */ if (c_p >= 0) { while (c_p >= 0) { if (fmt_str[c_p] == '0') { ret = OB_INVALID_NUMERIC; LOG_WARN("there has no digit that matches the 0(s) in the fmt str", K(ret), K(i), K(c_p)); break; } c_p--; } } if (i >= integer_start) { ret = OB_INVALID_NUMERIC; LOG_WARN("integer part is longer than fmt str", K(ret), K(i), K(c_p)); } } else { /* Do nothing */ } } return ret; } int ObNumberBuilder::build_integer_v2_(const char* str, const int64_t integer_start, const int64_t integer_end, const bool reduce_zero, const bool integer_zero, int& warning, ObNumberFmtModel* fmt) { int ret = OB_SUCCESS; if (OB_ISNULL(fmt)) { ret = build_integer_v2_(str, integer_start, integer_end, reduce_zero, integer_zero, warning); } else if (fmt->has_x_) { ret = build_hex_integer_(str, integer_start, integer_end, reduce_zero, fmt); } else { ret = build_integer_(str, integer_start, integer_end, reduce_zero, fmt); } return ret; } int ObNumberBuilder::build_decimal_( const char* str, const int64_t length, const int64_t decimal_start, const bool reduce_zero) { int ret = OB_SUCCESS; db_.reset(); int64_t skiped_zero_counter = 0; if (decimal_start < length && OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else { for (int64_t i = decimal_start; i < length; ++i) { char c = str[i]; if ('0' == c) { ++skiped_zero_counter; continue; } else { for (int64_t j = 0; j < skiped_zero_counter; ++j) { if (OB_FAIL(db_.push(0, reduce_zero))) { LOG_WARN("push to decimal builder fail", K(ret), K(j)); break; } } if (OB_FAIL(ret)) { break; } skiped_zero_counter = 0; } if (OB_FAIL(db_.push((uint8_t)(c - '0'), reduce_zero))) { LOG_WARN("push to decimal builder fail", K(ret), K(c)); break; } } } return ret; } int ObNumberBuilder::build_decimal_v2_(const char* str, const int64_t length, const int64_t decimal_start, const bool reduce_zero, const bool decimal_zero, int& warning) { int ret = OB_SUCCESS; static const uint32_t POWS[ObNumber::DIGIT_LEN] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; if (decimal_zero) { db_.reset(); } else if (OB_UNLIKELY(decimal_start <= length) && OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null", K(decimal_start), K(length), K(ret)); } else { uint32_t tmp = 0; int64_t idx = 0; int64_t decimal_end = length - 1; while (decimal_end >= decimal_start && str[decimal_end] == '0') { --decimal_end; } for (int64_t i = decimal_start; OB_SUCC(ret) && i <= decimal_end; ++i) { int32_t tmp_value = str[i] - '0'; if (OB_UNLIKELY(tmp_value < 0) || OB_UNLIKELY(tmp_value > 9)) { warning = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error: got ", K(ret), K(warning), K(str[i]), K(tmp_value)); } else { tmp += static_cast(POWS[idx++] * tmp_value); if (idx >= ObNumber::DIGIT_LEN || i == decimal_end) { if (OB_FAIL(db_.push_digit(tmp, reduce_zero))) { LOG_WARN("push to decimal builder fail", K(ret), K(i)); break; } tmp = 0; idx = 0; } } } } return ret; } int ObNumberBuilder::find_point_(const char* str, int64_t& length, int64_t& integer_start, int64_t& integer_end, int64_t& decimal_start, bool& negative, bool& integer_zero, bool& decimal_zero, int& warning) { int ret = OB_SUCCESS; int64_t i_integer_start = -2; int64_t dot_idx = -1; bool b_negative = false; bool b_integer_zero = true; bool b_decimal_zero = true; bool sign_appeared = false; bool digit_appeared = false; bool dot_appeared = false; int64_t i = 0; if (OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the str pointer is null", K(ret)); } else { for (i = 0; i < length && isspace(str[i]); ++i) ; for (; i + 1 < length && isspace(str[length - 1]); --length) ; if (OB_UNLIKELY(i == length)) { ret = OB_INVALID_NUMERIC; } else { for (; OB_SUCCESS == warning && i < length; ++i) { char c = str[i]; switch (c) { case '-': case '+': if (sign_appeared || digit_appeared || dot_appeared) { warning = OB_INVALID_NUMERIC; // LOG_DEBUG("invalid numeric", K(sign_appeared), K(digit_appeared), K(dot_appeared)); } else { if ('-' == c) { b_negative = true; } sign_appeared = true; } break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!dot_appeared) { b_integer_zero = false; } else { b_decimal_zero = false; } /* no break. */ case '0': if (-2 == i_integer_start) { i_integer_start = i; } digit_appeared = true; break; case '.': if (dot_appeared) { warning = OB_INVALID_NUMERIC; // LOG_DEBUG("invalid numeric", K(dot_appeared)); } else { if (!digit_appeared) { //".95" means "0.95" // i_integer_start and i_integer_end both will be -1 i_integer_start = -1; } dot_appeared = true; dot_idx = i; } break; default: warning = OB_INVALID_NUMERIC; // _LOG_DEBUG("invalid numeric default, c=%x", c); break; } } } if (OB_SUCC(ret)) { if (OB_SUCCESS != warning) { length = i - 1; } if (!dot_appeared) { dot_idx = length; } negative = b_negative; integer_zero = b_integer_zero; decimal_zero = b_decimal_zero; integer_start = i_integer_start; integer_end = dot_idx - 1; decimal_start = dot_idx + 1; ObString tmp_str(length, str); LOG_DEBUG("find v1", K(tmp_str), K(negative), K(integer_zero), K(decimal_zero), K(integer_start), K(dot_idx), K(i), K(length)); } } return ret; } int ObNumberBuilder::find_point_v2_(const char* str, int64_t& length, int64_t& integer_start, int64_t& integer_end, int64_t& decimal_start, bool& negative, bool& integer_zero, bool& decimal_zero, int& warning) { int ret = OB_SUCCESS; int64_t i_integer_start = -2; int64_t dot_idx = -1; bool b_negative = false; bool b_integer_zero = true; bool b_decimal_zero = true; int64_t i = 0; if (OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the str pointer is null", K(ret)); } else { for (i = 0; i < length && isspace(str[i]); ++i) ; for (; i + 1 < length && isspace(str[length - 1]); --length) ; if (OB_UNLIKELY(i == length)) { if (0 == i) { ret = OB_INVALID_NUMERIC; } else { // empty string is enabled warning = OB_INVALID_NUMERIC; } } else { if ('-' == str[i]) { b_negative = true; ++i; } else if ('+' == str[i]) { ++i; } if (i == length) { dot_idx = length; } else { const char* dot_pos = static_cast(memchr(str + i, '.', length - i)); if (NULL == dot_pos) { dot_idx = length; i_integer_start = i; b_integer_zero = false; b_decimal_zero = true; } else { dot_idx = dot_pos - str; i_integer_start = (i == dot_idx) ? -1 : i; // todo can be used b_integer_zero = ((dot_idx == i || ((dot_idx - i) == static_cast(strspn(str + i, "0")))) ? true : false); b_decimal_zero = (((dot_idx == length - 1) || ((length - 1 - dot_idx) == static_cast(strspn(str + dot_idx + 1, "0")))) ? true : false); } } } if (OB_SUCC(ret)) { negative = b_negative; integer_zero = b_integer_zero; decimal_zero = b_decimal_zero; integer_start = i_integer_start; integer_end = dot_idx - 1; decimal_start = dot_idx + 1; // ObString tmp_str(length, str); // LOG_DEBUG("find v2", K(tmp_str), K(negative), K(integer_zero), // K(decimal_zero), K(integer_start), K(dot_idx), K(i), K(length)); } } return ret; } int ObNumberBuilder::find_point_(const char* str, ObNumberFmtModel* fmt, char* new_str, int64_t& length, int64_t& integer_start, int64_t& integer_end, int64_t& decimal_start, bool& negative, bool& integer_zero, bool& decimal_zero, int64_t& comma_cnt) { int ret = OB_SUCCESS; int64_t i_integer_start = -2; int64_t dot_idx = -1; bool b_negative = false; bool b_integer_zero = true; bool b_decimal_zero = true; bool sign_appeared = false; bool digit_appeared = false; bool dot_appeared = false; bool dollar_appeared = false; int64_t heading_space = 0; int64_t trailing_space = 0; int64_t i = 0; int64_t new_len = 0; int64_t b_comma_cnt = 0; if (OB_ISNULL(str)) { ret = OB_INVALID_ARGUMENT; LIB_LOG(WARN, "the str pointer is null", K(ret)); } else { for (i = 0; i < length && isspace(str[i]); ++i) ; heading_space = i; for (; i + 1 < length && isspace(str[length - 1]); --length, ++trailing_space) ; if (OB_UNLIKELY(i == length)) { // to_number(' ', '9B9.9') => 0 if (!fmt->has_b_ || fmt->has_currency_ || fmt->has_sign_ || heading_space + trailing_space != fmt->fmt_len_ + 1) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error", K(ret), K(fmt->has_b_), K(heading_space), K(trailing_space), K(fmt->fmt_len_)); } else { new_str[0] = '0'; digit_appeared = true; dot_idx = 0; length = 1; i = 1; LIB_LOG(WARN, "ObNumber format:cast spaces to zero", K(ret)); } } else { for (; OB_SUCCESS == ret && i < length; ++i) { char c = str[i]; switch (c) { case '-': case '+': if (sign_appeared || ((!fmt->has_sign_ || fmt->sign_position_ == FmtFirst) && (digit_appeared || dot_appeared)) || (fmt->sign_position_ == FmtLast && (i != (length - 1)))) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error", K(ret), K(fmt->sign_position_), K(digit_appeared), K(dot_appeared), K(i)); } else { if ('-' == c) { b_negative = true; } else if (!fmt->has_sign_) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error:no sign in fmt str, but got '+'", K(ret)); } sign_appeared = true; } break; case 'a' ... 'f': case 'A' ... 'F': if (!fmt->has_x_) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error: got ", K(ret), K(c)); } /* no break. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!dot_appeared) { b_integer_zero = false; } else { b_decimal_zero = false; } /* no break. */ case '0': if (-2 == i_integer_start) { i_integer_start = new_len; } digit_appeared = true; new_str[new_len++] = c; break; case '.': if (dot_appeared) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error:dot appeared more than one time"); } else { if (!digit_appeared) { //".95" means "0.95" // i_integer_start and i_integer_end both will be -1 i_integer_start = -1; } dot_appeared = true; dot_idx = new_len; new_str[new_len++] = c; } break; case ',': if (dot_appeared) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error:comma appears at decimal part"); } else if (fmt->has_comma_) { new_str[new_len++] = ','; ++b_comma_cnt; } else { // ignore comma } break; case '$': if (dollar_appeared || dot_appeared || digit_appeared) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error:$ can only be the first valid character"); } else { dollar_appeared = true; } break; default: ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got format error: got ", K(ret), K(c)); break; } } } if (OB_SUCC(ret)) { if (!digit_appeared && (dollar_appeared || sign_appeared)) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got error according to fmt ", K(ret), K(digit_appeared), K(dollar_appeared)); } else if ((fmt->has_sign_ && !sign_appeared) || (fmt->has_currency_ && !dollar_appeared)) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got error according to fmt", K(ret), K(fmt->has_sign_), K(sign_appeared), K(fmt->has_currency_), K(dollar_appeared)); } else if (fmt->has_x_ && (b_negative || dot_appeared)) { ret = OB_INVALID_NUMERIC; LIB_LOG(WARN, "ObNumber got error according to fmt ", K(ret), K(dot_appeared), K(fmt->has_x_)); } else { if (!dot_appeared) { dot_idx = new_len; } negative = b_negative; integer_zero = b_integer_zero; decimal_zero = b_decimal_zero; integer_start = i_integer_start; integer_end = dot_idx - 1; decimal_start = dot_idx + 1; comma_cnt = b_comma_cnt; // to_number('12.34', '9.99') => error // to_number('1.32', '9999.9') => error // to_number('1.32', '9999.999') => 1.32 if (((fmt->dc_position_ > 0) && ((integer_end - integer_start + 1 - comma_cnt) > fmt->dc_position_)) || (fmt->has_x_ && new_len > fmt->fmt_len_) || (dot_appeared && ((new_len - decimal_start) > (fmt->dc_position_ > 0 ? (fmt->fmt_len_ - fmt->dc_position_ - 1) : 0)))) { LIB_LOG(WARN, "ObNumber got error according to fmt", K(integer_end), K(integer_start), K(fmt->dc_position_), K(dot_appeared), K(new_len), K(decimal_start), K(fmt->fmt_len_), K(fmt->dc_position_), K(comma_cnt)); ret = OB_INVALID_NUMERIC; } LIB_LOG(DEBUG, "ObNumber process fmt success", K(new_str), K(length), K(new_len), K(dot_appeared)); length = new_len; } } } return ret; } int64_t ObNumberBuilder::get_exp() const { return number_.d_.exp_; } int64_t ObNumberBuilder::get_length() const { return number_.d_.len_; } //////////////////////////////////////////////////////////////////////////////////////////////////// int ObDigitIterator::get_next_digit(uint32_t& digit, bool& from_integer, bool& last_decimal) { int ret = OB_SUCCESS; if (0 <= iter_exp_) { from_integer = true; if (iter_idx_ < iter_len_) { ret = get_digit(iter_idx_++, digit); } else { digit = 0; } --iter_exp_; } else { from_integer = false; if (-1 == iter_exp_) { if (iter_idx_ >= iter_len_) { ret = OB_ITER_END; } else { ret = get_digit(iter_idx_++, digit); last_decimal = (iter_idx_ == iter_len_); } } else { digit = 0; ++iter_exp_; } } return ret; } ObDigitIterator::NextDigitEnum ObDigitIterator::get_next_digit(uint32_t& digit) { NextDigitEnum nd_enum = ND_END; if (0 <= iter_exp_) { nd_enum = (0 == iter_idx_ ? ND_HEAD_INTEGER : ND_BODY_INTEGER); if (iter_idx_ < iter_len_) { digit = number_.get_digits()[iter_idx_++]; } else { digit = 0; } --iter_exp_; } else { if (-1 == iter_exp_) { if (iter_idx_ < iter_len_) { digit = number_.get_digits()[iter_idx_++]; nd_enum = (iter_idx_ == iter_len_ ? ND_TAIL_DECIMAL : ND_BODY_DECIMAL); } else { nd_enum = ND_END; } } else { digit = 0; ++iter_exp_; nd_enum = ND_BODY_DECIMAL; } } return nd_enum; } //////////////////////////////////////////////////////////////////////////////////////////////////// ObCalcVector::ObCalcVector() : base_(ObNumber::BASE), length_(0), digits_(buffer_) {} ObCalcVector::~ObCalcVector() {} ObCalcVector::ObCalcVector(const ObCalcVector& other) { LIB_LOG(DEBUG, "copy assignment invoked"); *this = other; } ObCalcVector& ObCalcVector::operator=(const ObCalcVector& other) { LIB_LOG(DEBUG, "operator = invoked"); if (this != &other) { base_ = other.base_; length_ = other.length_; digits_ = other.digits_; } return *this; } int ObCalcVector::init(const uint32_t desc, uint32_t* digits) { ObDigitIterator di; int ret = OB_SUCCESS; di.assign(desc, digits); bool head_zero = true; uint32_t digit = 0; bool from_integer = false; bool last_decimal = false; length_ = 0; digits_ = buffer_; while (OB_SUCCESS == (ret = di.get_next_digit(digit, from_integer, last_decimal))) { if (head_zero) { if (0 == digit) { continue; } else { head_zero = false; } } digits_[length_++] = digit; } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } return ret; } uint64_t ObCalcVector::at(const int64_t idx) const { uint64_t ret_digit = 0; if (OB_ISNULL(digits_)) { LOG_ERROR("the pointer is null"); } else if (OB_UNLIKELY(idx < 0 || idx > length_)) { LOG_ERROR("the param is invalid"); } else { ret_digit = digits_[idx]; } return ret_digit; } uint64_t ObCalcVector::base() const { return base_; } void ObCalcVector::set_base(const uint64_t base) { base_ = base; } int64_t ObCalcVector::size() const { return length_; } uint32_t* ObCalcVector::get_digits() { return digits_; } int ObCalcVector::normalize() { int64_t i = 0; int ret = OB_SUCCESS; if (length_ > 0 && OB_ISNULL(digits_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else { for (; i < length_; ++i) { if (0 != digits_[i]) { break; } } length_ = length_ - i; if (0 == length_) { digits_ = NULL; } else { digits_ = &digits_[i]; } } return ret; } int ObCalcVector::set(const int64_t idx, const uint64_t digit) { int ret = OB_SUCCESS; if (OB_UNLIKELY(0 > idx || idx >= length_ || base_ <= digit || NULL == digits_)) { LOG_ERROR("invalid param ", K(idx), K(length_), K(digit), K(base_)); ret = OB_INVALID_ARGUMENT; } else { digits_[idx] = (uint32_t)digit; } return ret; } int ObCalcVector::ensure(const int64_t size) { int ret = OB_SUCCESS; if (OB_ISNULL(buffer_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (OB_UNLIKELY(ObNumber::MAX_CALC_LEN < size)) { ret = OB_NUMERIC_OVERFLOW; } else if (OB_UNLIKELY(digits_ < &buffer_[0] || digits_ > &buffer_[ObNumber::MAX_CALC_LEN - 1])) { LOG_ERROR("digits is read only ", K(digits_), K(buffer_)); ret = OB_ERR_READ_ONLY; } else { length_ = size; } return ret; } int ObCalcVector::resize(const int64_t size) { int ret = OB_SUCCESS; if (OB_ISNULL(buffer_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else if (OB_UNLIKELY(ObNumber::MAX_CALC_LEN < size)) { ret = OB_NUMERIC_OVERFLOW; } else if (OB_UNLIKELY(digits_ < &buffer_[0] || digits_ > &buffer_[ObNumber::MAX_CALC_LEN - 1])) { LOG_ERROR("digits is read only", K(digits_), K(buffer_)); ret = OB_ERR_READ_ONLY; } else { MEMSET(digits_, 0, size * ITEM_SIZE(digits_)); length_ = size; } return ret; } ObCalcVector ObCalcVector::ref(const int64_t start, const int64_t end) const { ObCalcVector ret_calc_vec; if (OB_ISNULL(digits_)) { LOG_ERROR("the pinter is null"); } else { ret_calc_vec.length_ = end - start + 1; ret_calc_vec.digits_ = &digits_[start]; ret_calc_vec.set_base(this->base()); } return ret_calc_vec; } int ObCalcVector::assign(const ObCalcVector& other, const int64_t start, const int64_t end) { int ret = OB_SUCCESS; if (0 < (end - start + 1)) { if (OB_ISNULL(digits_)) { ret = OB_INVALID_ARGUMENT; LOG_ERROR("the pointer is null"); } else { MEMCPY(&digits_[start], other.digits_, (end - start + 1) * ITEM_SIZE(digits_)); } } return ret; } int64_t ObCalcVector::to_string(char* buffer, const int64_t length) const { int64_t pos = 0; if ((length_ > 0 && OB_ISNULL(digits_)) || length_ < 0) { databuff_printf(buffer, length, pos, "the value is invalid"); } else { databuff_printf( buffer, length, pos, "\"{length=%ld digits_ptr=%p buffer_ptr=%p digits=[", length_, digits_, buffer_); for (int64_t i = 0; i < length_; ++i) { databuff_printf(buffer, length, pos, "%u,", digits_[i]); } databuff_printf(buffer, length, pos, "]}\""); } return pos; } } // namespace number } // namespace common } // namespace oceanbase