Skip to content

Commit 36aecb4

Browse files
committed
Fix decimal floor/ceil (#63086)
1 parent c6dc5fc commit 36aecb4

1 file changed

Lines changed: 82 additions & 71 deletions

File tree

dbms/src/Functions/FunctionsRound.h

Lines changed: 82 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -199,77 +199,6 @@ enum class RoundingMode
199199
#endif
200200
};
201201

202-
/** Rounding functions for decimal values
203-
*/
204-
205-
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode, typename OutputType>
206-
struct DecimalRoundingComputation
207-
{
208-
static_assert(IsDecimal<T>);
209-
static const size_t data_count = 1;
210-
static size_t prepare(size_t scale) { return scale; }
211-
// compute need decimal_scale to interpret decimals
212-
static inline void compute(
213-
const T * __restrict in,
214-
size_t scale,
215-
OutputType * __restrict out,
216-
ScaleType decimal_scale)
217-
{
218-
static_assert(std::is_same_v<T, OutputType> || std::is_same_v<OutputType, Int64>);
219-
Float64 val = in->template toFloat<Float64>(decimal_scale);
220-
221-
if constexpr (scale_mode == ScaleMode::Positive)
222-
{
223-
val = val * scale;
224-
}
225-
else if constexpr (scale_mode == ScaleMode::Negative)
226-
{
227-
val = val / scale;
228-
}
229-
230-
if constexpr (rounding_mode == RoundingMode::Round)
231-
{
232-
val = round(val);
233-
}
234-
else if constexpr (rounding_mode == RoundingMode::Floor)
235-
{
236-
val = floor(val);
237-
}
238-
else if constexpr (rounding_mode == RoundingMode::Ceil)
239-
{
240-
val = ceil(val);
241-
}
242-
else if constexpr (rounding_mode == RoundingMode::Trunc)
243-
{
244-
val = trunc(val);
245-
}
246-
247-
248-
if constexpr (scale_mode == ScaleMode::Positive)
249-
{
250-
val = val / scale;
251-
}
252-
else if constexpr (scale_mode == ScaleMode::Negative)
253-
{
254-
val = val * scale;
255-
}
256-
257-
if constexpr (std::is_same_v<T, OutputType>)
258-
{
259-
*out = ToDecimal<Float64, T>(val, decimal_scale);
260-
}
261-
else if constexpr (std::is_same_v<OutputType, Int64>)
262-
{
263-
*out = static_cast<Int64>(val);
264-
}
265-
else
266-
{
267-
; // never arrived here
268-
}
269-
}
270-
};
271-
272-
273202
/** Rounding functions for integer values.
274203
*/
275204
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
@@ -333,6 +262,88 @@ struct IntegerRoundingComputation
333262
}
334263
};
335264

265+
/** Rounding functions for decimal values
266+
*/
267+
268+
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode, typename OutputType>
269+
struct DecimalRoundingComputation
270+
{
271+
static_assert(IsDecimal<T>);
272+
static const size_t data_count = 1;
273+
static size_t prepare(size_t scale) { return scale; }
274+
// compute need decimal_scale to interpret decimals
275+
static inline void compute(
276+
const T * __restrict in,
277+
size_t scale,
278+
OutputType * __restrict out,
279+
ScaleType decimal_scale)
280+
{
281+
static_assert(std::is_same_v<T, OutputType> || std::is_same_v<OutputType, Int64>);
282+
283+
using NativeType = T::NativeType;
284+
using Op = IntegerRoundingComputation<NativeType, rounding_mode, ScaleMode::Negative>;
285+
size_t scale_factor = pow(10, decimal_scale);
286+
287+
if constexpr (scale_mode == ScaleMode::Zero)
288+
{
289+
if (scale != 1)
290+
{
291+
throw Exception(
292+
"Logical error: unexpected 'scale' parameter passed to DecimalRoundingComputation",
293+
ErrorCodes::LOGICAL_ERROR);
294+
}
295+
296+
if constexpr (std::is_same_v<T, OutputType>)
297+
{
298+
Op::compute(&in->value, scale_factor, &out->value);
299+
}
300+
else if constexpr (std::is_same_v<OutputType, Int64>)
301+
{
302+
if constexpr (!std::is_same_v<T, Decimal256>)
303+
{
304+
if constexpr (rounding_mode == RoundingMode::Floor)
305+
{
306+
auto x = in->value;
307+
if (x < 0)
308+
x -= scale_factor - 1;
309+
*out = x / scale_factor;
310+
}
311+
else if constexpr (rounding_mode == RoundingMode::Ceil)
312+
{
313+
auto x = in->value;
314+
if (x >= 0)
315+
x += scale_factor - 1;
316+
*out = x / scale_factor;
317+
}
318+
else
319+
{
320+
throw Exception(
321+
"Logical error: unexpected 'rounding_mode' parameter passed to DecimalRoundingComputation",
322+
ErrorCodes::LOGICAL_ERROR);
323+
}
324+
}
325+
else
326+
{
327+
throw Exception(
328+
"Logical error: unexpected Type of DecimalRoundingComputation for INT result",
329+
ErrorCodes::LOGICAL_ERROR);
330+
}
331+
}
332+
else
333+
{
334+
throw Exception(
335+
"Logical error: unexpected OutputType of DecimalRoundingComputation",
336+
ErrorCodes::LOGICAL_ERROR);
337+
}
338+
}
339+
else
340+
{
341+
throw Exception(
342+
"Logical error: unexpected 'scale_mode' parameter passed to DecimalRoundingComputation",
343+
ErrorCodes::LOGICAL_ERROR);
344+
}
345+
}
346+
};
336347

337348
#if __SSE4_1__
338349

0 commit comments

Comments
 (0)