1#include <type_traits>
2#include <ext/bit_cast.h>
3#include <Functions/FunctionFactory.h>
4#include <Functions/FunctionUnaryArithmetic.h>
5
6namespace DB
7{
8
9template <typename T>
10inline std::enable_if_t<is_integral_v<T> && (sizeof(T) <= sizeof(UInt32)), T>
11roundDownToPowerOfTwo(T x)
12{
13 return x <= 0 ? 0 : (T(1) << (31 - __builtin_clz(x)));
14}
15
16template <typename T>
17inline std::enable_if_t<is_integral_v<T> && (sizeof(T) == sizeof(UInt64)), T>
18roundDownToPowerOfTwo(T x)
19{
20 return x <= 0 ? 0 : (T(1) << (63 - __builtin_clzll(x)));
21}
22
23template <typename T>
24inline std::enable_if_t<std::is_same_v<T, Float32>, T>
25roundDownToPowerOfTwo(T x)
26{
27 return ext::bit_cast<T>(ext::bit_cast<UInt32>(x) & ~((1ULL << 23) - 1));
28}
29
30template <typename T>
31inline std::enable_if_t<std::is_same_v<T, Float64>, T>
32roundDownToPowerOfTwo(T x)
33{
34 return ext::bit_cast<T>(ext::bit_cast<UInt64>(x) & ~((1ULL << 52) - 1));
35}
36
37/** For integer data types:
38 * - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(100) = 64, roundToExp2(64) = 64);
39 * - otherwise, return 0.
40 *
41 * For floating point data types: zero out mantissa, but leave exponent.
42 * - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(3) = 2);
43 * - negative powers are also used (example: roundToExp2(0.7) = 0.5);
44 * - if number is zero, return zero;
45 * - if number is less than zero, the result is symmetrical: roundToExp2(x) = -roundToExp2(-x). (example: roundToExp2(-0.3) = -0.25);
46 */
47
48template <typename T>
49struct RoundToExp2Impl
50{
51 using ResultType = T;
52
53 static inline T apply(T x)
54 {
55 return roundDownToPowerOfTwo<T>(x);
56 }
57
58#if USE_EMBEDDED_COMPILER
59 static constexpr bool compilable = false;
60#endif
61};
62
63struct NameRoundToExp2 { static constexpr auto name = "roundToExp2"; };
64using FunctionRoundToExp2 = FunctionUnaryArithmetic<RoundToExp2Impl, NameRoundToExp2, false>;
65
66template <> struct FunctionUnaryArithmeticMonotonicity<NameRoundToExp2> : PositiveMonotonicity {};
67
68void registerFunctionRoundToExp2(FunctionFactory & factory)
69{
70 factory.registerFunction<FunctionRoundToExp2>();
71}
72
73}
74