// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #ifndef DORIS_BE_SRC_RUNTIME_DECIMALV2_VALUE_H #define DORIS_BE_SRC_RUNTIME_DECIMALV2_VALUE_H #include #include #include #include #include #include #include #include #include "common/logging.h" #include "udf/udf.h" #include "util/hash_util.hpp" #include "util/mysql_global.h" namespace doris { typedef __int128_t int128_t; enum DecimalError { E_DEC_OK = 0, E_DEC_TRUNCATED = 1, E_DEC_OVERFLOW = 2, E_DEC_DIV_ZERO = 4, E_DEC_BAD_NUM = 8, E_DEC_OOM = 16, E_DEC_ERROR = 31, E_DEC_FATAL_ERROR = 30 }; enum DecimalRoundMode { HALF_UP = 1, HALF_EVEN = 2, CEILING = 3, FLOOR = 4, TRUNCATE = 5 }; class DecimalV2Value { public: friend DecimalV2Value operator+(const DecimalV2Value& v1, const DecimalV2Value& v2); friend DecimalV2Value operator-(const DecimalV2Value& v1, const DecimalV2Value& v2); friend DecimalV2Value operator*(const DecimalV2Value& v1, const DecimalV2Value& v2); friend DecimalV2Value operator/(const DecimalV2Value& v1, const DecimalV2Value& v2); friend std::istream& operator>>(std::istream& ism, DecimalV2Value& decimal_value); friend DecimalV2Value operator-(const DecimalV2Value& v); static constexpr int32_t PRECISION = 27; static constexpr int32_t SCALE = 9; static constexpr int32_t SCALE_TRIM_ARRAY[SCALE + 1] = { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 }; static constexpr uint32_t ONE_BILLION = 1000000000; static constexpr int64_t MAX_INT_VALUE = 999999999999999999; static constexpr int32_t MAX_FRAC_VALUE = 999999999; static constexpr int64_t MAX_INT64 = 9223372036854775807ll; // In sqrt, the integer part and the decimal part of the square root to be solved separately are // multiplied by the PRECISION/2 power of 10, so that they can be placed in an int128_t variable static const int128_t SQRT_MOLECULAR_MAGNIFICATION; // sqrt(ONE_BILLION) * pow(10, PRECISION/2 - SCALE), it is used to calculate SCALE of the sqrt result static const int128_t SQRT_DENOMINATOR; static const int128_t MAX_DECIMAL_VALUE = static_cast(MAX_INT64) * ONE_BILLION + MAX_FRAC_VALUE; DecimalV2Value() = default; inline const int128_t& value() const { return _value; } inline int128_t& value() { return _value; } DecimalV2Value(const std::string& decimal_str) { parse_from_str(decimal_str.c_str(), decimal_str.size()); } DecimalV2Value(const std::string_view& decimal_str) { parse_from_str(decimal_str.data(), decimal_str.size()); } // Construct from olap engine DecimalV2Value(int64_t int_value, int64_t frac_value) { from_olap_decimal(int_value, frac_value); } inline bool from_olap_decimal(int64_t int_value, int64_t frac_value) { bool success = true; bool is_negative = (int_value < 0 || frac_value < 0); if (is_negative) { int_value = std::abs(int_value); frac_value = std::abs(frac_value); } //if (int_value > MAX_INT_VALUE) { // int_value = MAX_INT_VALUE; // success = false; //} if (frac_value > MAX_FRAC_VALUE) { frac_value = MAX_FRAC_VALUE; success = false; } _value = static_cast(int_value) * ONE_BILLION + frac_value; if (is_negative) _value = -_value; return success; } explicit DecimalV2Value(int128_t int_value) { _value = int_value; } void set_value(int128_t value) { _value = value; } DecimalV2Value& assign_from_float(const float float_value) { _value = static_cast(float_value * ONE_BILLION); return *this; } DecimalV2Value& assign_from_double(const double double_value) { _value = static_cast(double_value * ONE_BILLION); return *this; } // These cast functions are needed in "functions.cc", which is generated by python script. // e.g. "ComputeFunctions::Cast_DecimalV2Value_double()" // Discard the scale part // ATTN: invoker must make sure no OVERFLOW operator int64_t() const { return static_cast(_value / ONE_BILLION); } // These cast functions are needed in "functions.cc", which is generated by python script. // e.g. "ComputeFunctions::Cast_DecimalV2Value_double()" // Discard the scale part // ATTN: invoker must make sure no OVERFLOW operator int128_t() const { return static_cast(_value / ONE_BILLION); } operator bool() const { return _value != 0; } operator int8_t() const { return static_cast(operator int64_t()); } operator int16_t() const { return static_cast(operator int64_t()); } operator int32_t() const { return static_cast(operator int64_t()); } operator size_t() const { return static_cast(operator int64_t()); } operator float() const { return (float)operator double(); } operator double() const { std::string str_buff = to_string(); double result = std::strtod(str_buff.c_str(), nullptr); return result; } DecimalV2Value& operator+=(const DecimalV2Value& other); // To be Compatible with OLAP // ATTN: NO-OVERFLOW should be guaranteed. int64_t int_value() const { return operator int64_t(); } // To be Compatible with OLAP // NOTE: return a negative value if decimal is negative. // ATTN: the max length of fraction part in OLAP is 9, so the 'big digits' except the first one // will be truncated. int32_t frac_value() const { return static_cast(_value % ONE_BILLION); } bool operator==(const DecimalV2Value& other) const { return _value == other.value(); } bool operator!=(const DecimalV2Value& other) const { return _value != other.value(); } bool operator<=(const DecimalV2Value& other) const { return _value <= other.value(); } bool operator>=(const DecimalV2Value& other) const { return _value >= other.value(); } bool operator<(const DecimalV2Value& other) const { return _value < other.value(); } bool operator>(const DecimalV2Value& other) const { return _value > other.value(); } // change to maximum value for given precision and scale // precision/scale - see decimal_bin_size() below // to - decimal where where the result will be stored void to_max_decimal(int precision, int frac); void to_min_decimal(int precision, int frac) { to_max_decimal(precision, frac); if (_value > 0) _value = -_value; } // The maximum of fraction part is "scale". // If the length of fraction part is less than "scale", '0' will be filled. std::string to_string(int scale) const; int32_t to_buffer(char* buffer, int scale) const; // Output actual "scale", remove ending zeroes. std::string to_string() const; // Convert string to decimal // @param from - value to convert. Doesn't have to be \0 terminated! // will stop at the fist non-digit char(nor '.' 'e' 'E'), // or reaches the length // @param length - maximum length // @return error number. // // E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM // In case of E_DEC_FATAL_ERROR *to is set to decimal zero // (to make error handling easier) // // e.g. "1.2" ".2" "1.2e-3" "1.2e3" int parse_from_str(const char* decimal_str, int32_t length); std::string get_debug_info() const { return to_string(); } static DecimalV2Value get_min_decimal() { return DecimalV2Value(-MAX_INT_VALUE, MAX_FRAC_VALUE); } static DecimalV2Value get_max_decimal() { return DecimalV2Value(MAX_INT_VALUE, MAX_FRAC_VALUE); } static DecimalV2Value from_decimal_val(const DecimalV2Val& val) { return DecimalV2Value(val.value()); } void to_decimal_val(DecimalV2Val* value) const { value->val = _value; } // Solve Square root for int128 static DecimalV2Value sqrt(const DecimalV2Value& v); // set DecimalV2Value to zero void set_to_zero() { _value = 0; } void to_abs_value() { if (_value < 0) _value = -_value; } uint32_t hash(uint32_t seed) const { return HashUtil::hash(&_value, sizeof(_value), seed); } int32_t precision() const { return PRECISION; } int32_t scale() const { return SCALE; } bool greater_than_scale(int scale); int round(DecimalV2Value* to, int scale, DecimalRoundMode mode); inline static int128_t get_scale_base(int scale) { static const int128_t values[] = { static_cast(1ll), static_cast(10ll), static_cast(100ll), static_cast(1000ll), static_cast(10000ll), static_cast(100000ll), static_cast(1000000ll), static_cast(10000000ll), static_cast(100000000ll), static_cast(1000000000ll), static_cast(10000000000ll), static_cast(100000000000ll), static_cast(1000000000000ll), static_cast(10000000000000ll), static_cast(100000000000000ll), static_cast(1000000000000000ll), static_cast(10000000000000000ll), static_cast(100000000000000000ll), static_cast(1000000000000000000ll), static_cast(1000000000000000000ll) * 10ll, static_cast(1000000000000000000ll) * 100ll, static_cast(1000000000000000000ll) * 1000ll, static_cast(1000000000000000000ll) * 10000ll, static_cast(1000000000000000000ll) * 100000ll, static_cast(1000000000000000000ll) * 1000000ll, static_cast(1000000000000000000ll) * 10000000ll, static_cast(1000000000000000000ll) * 100000000ll, static_cast(1000000000000000000ll) * 1000000000ll, static_cast(1000000000000000000ll) * 10000000000ll, static_cast(1000000000000000000ll) * 100000000000ll, static_cast(1000000000000000000ll) * 1000000000000ll, static_cast(1000000000000000000ll) * 10000000000000ll, static_cast(1000000000000000000ll) * 100000000000000ll, static_cast(1000000000000000000ll) * 1000000000000000ll, static_cast(1000000000000000000ll) * 10000000000000000ll, static_cast(1000000000000000000ll) * 100000000000000000ll, static_cast(1000000000000000000ll) * 100000000000000000ll * 10ll, static_cast(1000000000000000000ll) * 100000000000000000ll * 100ll, static_cast(1000000000000000000ll) * 100000000000000000ll * 1000ll}; if (scale >= 0 && scale < 38) return values[scale]; return -1; // Overflow } bool is_zero() const { return _value == 0; } private: int128_t _value; }; DecimalV2Value operator+(const DecimalV2Value& v1, const DecimalV2Value& v2); DecimalV2Value operator-(const DecimalV2Value& v1, const DecimalV2Value& v2); DecimalV2Value operator*(const DecimalV2Value& v1, const DecimalV2Value& v2); DecimalV2Value operator/(const DecimalV2Value& v1, const DecimalV2Value& v2); DecimalV2Value operator%(const DecimalV2Value& v1, const DecimalV2Value& v2); DecimalV2Value operator-(const DecimalV2Value& v); std::ostream& operator<<(std::ostream& os, DecimalV2Value const& decimal_value); std::istream& operator>>(std::istream& ism, DecimalV2Value& decimal_value); std::size_t hash_value(DecimalV2Value const& value); } // end namespace doris namespace std { template <> struct hash { size_t operator()(const doris::DecimalV2Value& v) const { return doris::hash_value(v); } }; } // namespace std #endif // DORIS_BE_SRC_RUNTIME_DECIMALV2_VALUE_H