#include #include #ifdef __SSE2__ #define LIBDIVIDE_USE_SSE2 1 #endif #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } template struct ModuloImpl { using ResultType = typename NumberTraits::ResultOfModulo::Type; template static inline Result apply(A a, B b) { throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger::Type(a), typename NumberTraits::ToInteger::Type(b)); return typename NumberTraits::ToInteger::Type(a) % typename NumberTraits::ToInteger::Type(b); } #if USE_EMBEDDED_COMPILER static constexpr bool compilable = false; /// don't know how to throw from LLVM IR #endif }; template struct ModuloByConstantImpl : BinaryOperationImplBase> { using ResultType = typename ModuloImpl::ResultType; static void vector_constant(const PaddedPODArray & a, B b, PaddedPODArray & c) { if (unlikely(b == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" if (unlikely((std::is_signed_v && b == -1) || b == 1)) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = 0; return; } #pragma GCC diagnostic pop libdivide::divider divider(b); /// Here we failed to make the SSE variant from libdivide give an advantage. size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = a[i] - (a[i] / divider) * b; /// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved. } }; /** 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. */ 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 = FunctionBinaryArithmetic; void registerFunctionModulo(FunctionFactory & factory) { factory.registerFunction(); } }