Remove trailing zeros from Decimal serialization #15794

This commit is contained in:
Alexey Milovidov 2021-08-15 08:29:31 +03:00
parent ef803f14a1
commit 60dccce818
4 changed files with 95 additions and 14 deletions

View File

@ -277,5 +277,4 @@ GTEST_TEST(WideInteger, DecimalFormatting)
Int128 fractional = DecimalUtils::getFractionalPart(x, 2);
EXPECT_EQ(fractional, 40);
EXPECT_EQ(decimalFractional(fractional, 2), "40");
}

View File

@ -901,30 +901,63 @@ inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTim
inline void writeText(const UUID & x, WriteBuffer & buf) { writeUUIDText(x, buf); }
template <typename T>
String decimalFractional(const T & x, UInt32 scale)
void writeDecimalFractional(const T & x, UInt32 scale, WriteBuffer & ostr)
{
/// If it's big integer, but the number of digits is small,
/// use the implementation for smaller integers for more efficient arithmetic.
if constexpr (std::is_same_v<T, Int256>)
{
if (x <= std::numeric_limits<UInt32>::max())
return decimalFractional(static_cast<UInt32>(x), scale);
{
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr);
return;
}
else if (x <= std::numeric_limits<UInt64>::max())
return decimalFractional(static_cast<UInt64>(x), scale);
{
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr);
return;
}
else if (x <= std::numeric_limits<UInt128>::max())
return decimalFractional(static_cast<UInt128>(x), scale);
{
writeDecimalFractional(static_cast<UInt128>(x), scale, ostr);
return;
}
}
else if constexpr (std::is_same_v<T, Int128>)
{
if (x <= std::numeric_limits<UInt32>::max())
return decimalFractional(static_cast<UInt32>(x), scale);
{
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr);
return;
}
else if (x <= std::numeric_limits<UInt64>::max())
return decimalFractional(static_cast<UInt64>(x), scale);
{
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr);
return;
}
}
String str(scale, '0');
constexpr size_t max_digits = std::numeric_limits<T>::digits10;
assert(scale <= max_digits);
char buf[max_digits];
memset(buf, '0', scale);
T value = x;
for (Int32 pos = scale - 1; pos >= 0; --pos, value /= 10)
str[pos] += static_cast<char>(value % 10);
return str;
Int32 last_nonzero_pos = 0;
for (Int32 pos = scale - 1; pos >= 0; --pos)
{
auto remainder = value % 10;
value /= 10;
if (remainder != 0 && last_nonzero_pos == 0)
last_nonzero_pos = pos;
buf[pos] += static_cast<char>(remainder);
}
writeChar('.', ostr);
ostr.write(buf, last_nonzero_pos + 1);
}
template <typename T>
@ -941,10 +974,9 @@ void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr)
if (scale)
{
writeChar('.', ostr);
part = DecimalUtils::getFractionalPart(x, scale);
String fractional = decimalFractional(part, scale);
ostr.write(fractional.data(), scale);
if (part)
writeDecimalFractional(part, scale, ostr);
}
}

View File

@ -0,0 +1,32 @@
-- { echo }
SELECT 1.123::Decimal64(1);
1.1
SELECT 1.123::Decimal64(2);
1.12
SELECT 1.123::Decimal64(3);
1.123
SELECT 1.123::Decimal64(4);
1.123
SELECT 1.123::Decimal64(5);
1.123
SELECT 1.123::Decimal64(10);
1.123
SELECT 1::Decimal64(0);
1
SELECT 1::Decimal64(1);
1
SELECT 1::Decimal64(10);
1
SELECT 1.1234567::Decimal32(8);
1.1234567
SELECT 1.1234567890::Decimal64(10);
1.123456789
SELECT 1.1234567890::Decimal128(10);
1.123456789
SELECT 1.1234567890::Decimal256(10);
1.123456789
SELECT 1.123456789012345678901::Decimal256(20);
1.1234567890123456789
SELECT 1.123456789012345678901::Decimal256(22);
1.123456789012345678901

View File

@ -0,0 +1,18 @@
-- { echo }
SELECT 1.123::Decimal64(1);
SELECT 1.123::Decimal64(2);
SELECT 1.123::Decimal64(3);
SELECT 1.123::Decimal64(4);
SELECT 1.123::Decimal64(5);
SELECT 1.123::Decimal64(10);
SELECT 1::Decimal64(0);
SELECT 1::Decimal64(1);
SELECT 1::Decimal64(10);
SELECT 1.1234567::Decimal32(8);
SELECT 1.1234567890::Decimal64(10);
SELECT 1.1234567890::Decimal128(10);
SELECT 1.1234567890::Decimal256(10);
SELECT 1.123456789012345678901::Decimal256(20);
SELECT 1.123456789012345678901::Decimal256(22);