/*
* 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;
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)
{
return std::tuple(precision, scale);
}
else if (scale < 0)
{
return std::tuple(GlutenDecimalUtils::MAX_PRECISION, scale);
}
else
{
auto intDigits = precision - scale;
auto minScaleValue = std::min(scale, GlutenDecimalUtils::MINIMUM_ADJUSTED_SCALE);
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)
{
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);
}
}
};
}