#include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } namespace { /// Optimizations for integer modulo by a constant. template struct ModuloByConstantImpl : BinaryOperation> { using Op = ModuloImpl; using ResultType = typename Op::ResultType; static const constexpr bool allow_fixed_string = false; static const constexpr bool allow_string_integer = false; template static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap) { if constexpr (op_case == OpCase::RightConstant) { if (right_nullmap && (*right_nullmap)[0]) return; vectorConstant(a, *b, c, size); } else { if (right_nullmap) { for (size_t i = 0; i < size; ++i) if ((*right_nullmap)[i]) c[i] = ResultType(); else apply(a, b, c, i); } else for (size_t i = 0; i < size; ++i) apply(a, b, c, i); } } static ResultType process(A a, B b) { return Op::template apply(a, b); } static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size) { /// 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] = static_cast(src[i]); return; } if (unlikely(static_cast(b) == 0)) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division by zero"); /// Division by min negative value. if (std::is_signed_v && b == std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division by the most negative number"); /// Modulo of division by negative number is the same as the positive number. if (b < 0) b = -b; /// Here we failed to make the SSE variant from libdivide give an advantage. if (b & (b - 1)) { libdivide::divider divider(static_cast(b)); for (size_t i = 0; i < size; ++i) { /// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved. dst[i] = static_cast(src[i] - (src[i] / divider) * b); } } else { // gcc libdivide doesn't work well for pow2 division auto mask = b - 1; for (size_t i = 0; i < size; ++i) dst[i] = static_cast(src[i] & mask); } } private: template static inline void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i) { if constexpr (op_case == OpCase::Vector) c[i] = Op::template apply(a[i], b[i]); else c[i] = Op::template apply(*a, b[i]); } }; template struct ModuloLegacyByConstantImpl : ModuloByConstantImpl { using Op = ModuloLegacyImpl; }; } /** 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; REGISTER_FUNCTION(Modulo) { factory.registerFunction(); factory.registerAlias("mod", "modulo", FunctionFactory::CaseInsensitive); } struct NameModuloLegacy { static constexpr auto name = "moduloLegacy"; }; using FunctionModuloLegacy = BinaryArithmeticOverloadResolver; REGISTER_FUNCTION(ModuloLegacy) { factory.registerFunction(); } struct NamePositiveModulo { static constexpr auto name = "positiveModulo"; }; using FunctionPositiveModulo = BinaryArithmeticOverloadResolver; REGISTER_FUNCTION(PositiveModulo) { factory.registerFunction(FunctionDocumentation { .description=R"( Calculates the remainder when dividing `a` by `b`. Similar to function `modulo` except that `positiveModulo` always return non-negative number. Returns the difference between `a` and the nearest integer not greater than `a` divisible by `b`. In other words, the function returning the modulus (modulo) in the terms of Modular Arithmetic. )", .examples{{"positiveModulo", "SELECT positiveModulo(-1, 10);", ""}}, .categories{"Arithmetic"}}, FunctionFactory::CaseInsensitive); factory.registerAlias("positive_modulo", "positiveModulo", FunctionFactory::CaseInsensitive); /// Compatibility with Spark: factory.registerAlias("pmod", "positiveModulo", FunctionFactory::CaseInsensitive); } }