| /* |
| /* |
| * 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. |
| */ |
| #pragma once |
| |
| |
| namespace local_engine |
| { |
| |
| class GlutenDecimalUtils |
| { |
| public: |
| static constexpr size_t MAX_PRECISION = 38; |
| static constexpr size_t MAX_SCALE = 38; |
| static constexpr auto system_Default = std::tuple(MAX_PRECISION, 18); |
| static constexpr auto user_Default = std::tuple(10, 0); |
| static constexpr size_t MINIMUM_ADJUSTED_SCALE = 6; |
| |
| // The decimal types compatible with other numeric types |
| static constexpr auto BOOLEAN_DECIMAL = std::tuple(1, 0); |
| static constexpr auto BYTE_DECIMAL = std::tuple(3, 0); |
| static constexpr auto SHORT_DECIMAL = std::tuple(5, 0); |
| static constexpr auto INT_DECIMAL = std::tuple(10, 0); |
| static constexpr auto LONG_DECIMAL = std::tuple(20, 0); |
| static constexpr auto FLOAT_DECIMAL = std::tuple(14, 7); |
| static constexpr auto DOUBLE_DECIMAL = std::tuple(30, 15); |
| static constexpr auto BIGINT_DECIMAL = std::tuple(MAX_PRECISION, 0); |
| |
| static std::tuple<size_t, size_t> adjustPrecisionScale(size_t precision, size_t scale) |
| { |
| if (precision <= MAX_PRECISION) |
| { |
| // Adjustment only needed when we exceed max precision |
| return std::tuple(precision, scale); |
| } |
| else if (scale < 0) |
| { |
| // Decimal can have negative scale (SPARK-24468). In this case, we cannot allow a precision |
| // loss since we would cause a loss of digits in the integer part. |
| // In this case, we are likely to meet an overflow. |
| return std::tuple(GlutenDecimalUtils::MAX_PRECISION, scale); |
| } |
| else |
| { |
| // Precision/scale exceed maximum precision. Result must be adjusted to MAX_PRECISION. |
| auto intDigits = precision - scale; |
| // If original scale is less than MINIMUM_ADJUSTED_SCALE, use original scale value; otherwise |
| // preserve at least MINIMUM_ADJUSTED_SCALE fractional digits |
| auto minScaleValue = std::min(scale, GlutenDecimalUtils::MINIMUM_ADJUSTED_SCALE); |
| // The resulting scale is the maximum between what is available without causing a loss of |
| // digits for the integer part of the decimal and the minimum guaranteed scale, which is |
| // computed above |
| auto adjustedScale = std::max(GlutenDecimalUtils::MAX_PRECISION - intDigits, minScaleValue); |
| |
| return std::tuple(GlutenDecimalUtils::MAX_PRECISION, adjustedScale); |
| } |
| } |
| |
| static std::tuple<size_t, size_t> dividePrecisionScale(size_t p1, size_t s1, size_t p2, size_t s2, bool allowPrecisionLoss) |
| { |
| if (allowPrecisionLoss) |
| { |
| // Precision: p1 - s1 + s2 + max(6, s1 + p2 + 1) |
| // Scale: max(6, s1 + p2 + 1) |
| const size_t intDig = p1 - s1 + s2; |
| const size_t scale = std::max(MINIMUM_ADJUSTED_SCALE, s1 + p2 + 1); |
| const size_t precision = intDig + scale; |
| return adjustPrecisionScale(precision, scale); |
| } |
| else |
| { |
| auto intDig = std::min(MAX_SCALE, p1 - s1 + s2); |
| auto decDig = std::min(MAX_SCALE, std::max(static_cast<size_t>(6), s1 + p2 + 1)); |
| auto diff = (intDig + decDig) - MAX_SCALE; |
| if (diff > 0) |
| { |
| decDig -= diff / 2 + 1; |
| intDig = MAX_SCALE - decDig; |
| } |
| return std::tuple(intDig + decDig, decDig); |
| } |
| } |
| |
| |
| }; |
| |
| } |