1#pragma once
2// Moved Decimal-related functions out from Core/Types.h to reduce compilation time.
3
4#include <Core/Types.h>
5#include <Common/intExp.h>
6
7#include <limits>
8
9class DateLUTImpl;
10
11namespace DB
12{
13
14namespace DecimalUtils
15{
16
17static constexpr size_t minPrecision() { return 1; }
18template <typename T> static constexpr size_t maxPrecision() { return 0; }
19template <> constexpr size_t maxPrecision<Decimal32>() { return 9; }
20template <> constexpr size_t maxPrecision<Decimal64>() { return 18; }
21template <> constexpr size_t maxPrecision<Decimal128>() { return 38; }
22
23template <typename T> T scaleMultiplier(UInt32 scale);
24template <> inline Int32 scaleMultiplier<Int32>(UInt32 scale) { return common::exp10_i32(scale); }
25template <> inline Int64 scaleMultiplier<Int64>(UInt32 scale) { return common::exp10_i64(scale); }
26template <> inline Int128 scaleMultiplier<Int128>(UInt32 scale) { return common::exp10_i128(scale); }
27
28/** Components of DecimalX value:
29 * whole - represents whole part of decimal, can be negatve or positive.
30 * fractional - for fractional part of decimal, always positive.
31 */
32template <typename T>
33struct DecimalComponents
34{
35 T whole;
36 T fractional;
37};
38
39/** Make a decimal value from whole and fractional components with given scale multiplier.
40 * where scale_multiplier = scaleMultiplier<T>(scale)
41 * this is to reduce number of calls to scaleMultiplier when scale is known.
42 *
43 * Sign of `whole` controls sign of result: negative whole => negative result, positive whole => positive result.
44 * Sign of `fractional` is expected to be positive, otherwise result is undefined.
45 * If `scale` is to big (scale > maxPrecision<DecimalType::NativeType>), result is undefined.
46 */
47template <typename DecimalType>
48DecimalType decimalFromComponentsWithMultiplier(const typename DecimalType::NativeType & whole,
49 const typename DecimalType::NativeType & fractional,
50 typename DecimalType::NativeType scale_multiplier)
51{
52 using T = typename DecimalType::NativeType;
53 const auto fractional_sign = whole < 0 ? -1 : 1;
54
55 const T value = whole * scale_multiplier + fractional_sign * (fractional % scale_multiplier);
56 return DecimalType(value);
57}
58
59/** Make a decimal value from whole and fractional components with given scale.
60 *
61 * @see `decimalFromComponentsWithMultiplier` for details.
62 */
63template <typename DecimalType>
64DecimalType decimalFromComponents(const typename DecimalType::NativeType & whole, const typename DecimalType::NativeType & fractional, UInt32 scale)
65{
66 using T = typename DecimalType::NativeType;
67
68 return decimalFromComponentsWithMultiplier<DecimalType>(whole, fractional, scaleMultiplier<T>(scale));
69}
70
71/** Make a decimal value from whole and fractional components with given scale.
72 * @see `decimalFromComponentsWithMultiplier` for details.
73 */
74template <typename DecimalType>
75DecimalType decimalFromComponents(const DecimalComponents<typename DecimalType::NativeType> & components, UInt32 scale)
76{
77 return decimalFromComponents<DecimalType>(components.whole, components.fractional, scale);
78}
79
80/** Split decimal into whole and fractional parts with given scale_multiplier.
81 * This is an optimization to reduce number of calls to scaleMultiplier on known scale.
82 */
83template <typename DecimalType>
84DecimalComponents<typename DecimalType::NativeType> splitWithScaleMultiplier(const DecimalType & decimal, typename DecimalType::NativeType scale_multiplier)
85{
86 using T = typename DecimalType::NativeType;
87 const auto whole = decimal.value / scale_multiplier;
88 auto fractional = decimal.value % scale_multiplier;
89 if (fractional < T(0))
90 fractional *= T(-1);
91
92 return {whole, fractional};
93}
94
95/// Split decimal into components: whole and fractional part, @see `DecimalComponents` for details.
96template <typename DecimalType>
97DecimalComponents<typename DecimalType::NativeType> split(const DecimalType & decimal, UInt32 scale)
98{
99 if (scale == 0)
100 {
101 return {decimal.value, 0};
102 }
103 return splitWithScaleMultiplier(decimal, scaleMultiplier<typename DecimalType::NativeType>(scale));
104}
105
106/** Get whole part from decimal.
107 *
108 * Sign of result follows sign of `decimal` value.
109 * If scale is to big, result is undefined.
110 */
111template <typename DecimalType>
112typename DecimalType::NativeType getWholePart(const DecimalType & decimal, size_t scale)
113{
114 if (scale == 0)
115 return decimal.value;
116
117 return decimal.value / scaleMultiplier<typename DecimalType::NativeType>(scale);
118}
119
120/** Get fractional part from decimal
121 *
122 * Result is always positive.
123 * If scale is to big, result is undefined.
124 */
125template <typename DecimalType>
126typename DecimalType::NativeType getFractionalPart(const DecimalType & decimal, size_t scale)
127{
128 using T = typename DecimalType::NativeType;
129
130 if (scale == 0)
131 return 0;
132
133 T result = decimal.value;
134 if (result < T(0))
135 result *= T(-1);
136
137 return result % scaleMultiplier<T>(scale);
138}
139
140}
141
142}
143