#include #include #include #include namespace DB { namespace ErrorCodes { extern const int NOT_IMPLEMENTED; } namespace { template requires std::is_integral_v && (sizeof(T) <= sizeof(UInt32)) inline T roundDownToPowerOfTwo(T x) { return x <= 0 ? 0 : (T(1) << (31 - __builtin_clz(x))); } template requires std::is_integral_v && (sizeof(T) == sizeof(UInt64)) inline T roundDownToPowerOfTwo(T x) { return x <= 0 ? 0 : (T(1) << (63 - __builtin_clzll(x))); } template requires std::is_same_v inline T roundDownToPowerOfTwo(T x) { return bit_cast(bit_cast(x) & ~((1ULL << 23) - 1)); } template requires std::is_same_v inline T roundDownToPowerOfTwo(T x) { return bit_cast(bit_cast(x) & ~((1ULL << 52) - 1)); } template requires is_big_int_v inline T roundDownToPowerOfTwo(T) { throw Exception(ErrorCodes::NOT_IMPLEMENTED, "roundToExp2() for big integers is not implemented"); } /** For integer data types: * - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(100) = 64, roundToExp2(64) = 64); * - otherwise, return 0. * * For floating point data types: zero out mantissa, but leave exponent. * - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(3) = 2); * - negative powers are also used (example: roundToExp2(0.7) = 0.5); * - if number is zero, return zero; * - if number is less than zero, the result is symmetrical: roundToExp2(x) = -roundToExp2(-x). (example: roundToExp2(-0.3) = -0.25); */ template struct RoundToExp2Impl { using ResultType = T; static constexpr const bool allow_string_or_fixed_string = false; static inline T apply(T x) { return roundDownToPowerOfTwo(x); } #if USE_EMBEDDED_COMPILER static constexpr bool compilable = false; #endif }; struct NameRoundToExp2 { static constexpr auto name = "roundToExp2"; }; using FunctionRoundToExp2 = FunctionUnaryArithmetic; } template <> struct FunctionUnaryArithmeticMonotonicity : PositiveMonotonicity {}; REGISTER_FUNCTION(RoundToExp2) { factory.registerFunction(); } }