#include #include #if defined(__SSE2__) # define LIBDIVIDE_SSE2 1 #endif #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } namespace { /// Optimizations for integer modulo by a constant. template struct ModuloByConstantImpl : BinaryOperation> { using ResultType = typename ModuloImpl::ResultType; static const constexpr bool allow_fixed_string = false; static NO_INLINE void vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" /// Modulo with too small divisor. if (unlikely((std::is_signed_v && b == -1) || b == 1)) { for (size_t i = 0; i < size; ++i) dst[i] = 0; return; } /// Modulo with too large divisor. if (unlikely(b > std::numeric_limits::max() || (std::is_signed_v && std::is_signed_v && b < std::numeric_limits::lowest()))) { for (size_t i = 0; i < size; ++i) dst[i] = src[i]; return; } #pragma GCC diagnostic pop if (unlikely(static_cast(b) == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); libdivide::divider divider(b); /// Here we failed to make the SSE variant from libdivide give an advantage. if (b & (b - 1)) { for (size_t i = 0; i < size; ++i) dst[i] = src[i] - (src[i] / divider) * b; /// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved. } else { // gcc libdivide doesn't work well for pow2 division auto mask = b - 1; for (size_t i = 0; i < size; ++i) dst[i] = src[i] & mask; } } }; } /** Specializations are specified for dividing numbers of the type UInt64 and UInt32 by the numbers of the same sign. * Can be expanded to all possible combinations, but more code is needed. */ namespace impl_ { template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; template <> struct BinaryOperationImpl> : ModuloByConstantImpl {}; } struct NameModulo { static constexpr auto name = "modulo"; }; using FunctionModulo = BinaryArithmeticOverloadResolver; void registerFunctionModulo(FunctionFactory & factory) { factory.registerFunction(); factory.registerAlias("mod", "modulo", FunctionFactory::CaseInsensitive); } }