// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // This file is copied from // https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/Modulo.cpp // and modified by Doris #ifdef __SSE2__ #define LIBDIVIDE_SSE2 1 #endif #include #include "common/status.h" #include "vec/functions/function_binary_arithmetic.h" #include "vec/functions/function_binary_arithmetic_to_null_type.h" #include "vec/functions/simple_function_factory.h" namespace doris::vectorized { template struct ModuloImpl { using ResultType = typename NumberTraits::ResultOfModulo::Type; template static inline Result apply(A a, B b, NullMap& null_map, size_t index) { if constexpr (std::is_floating_point_v) { null_map[index] = 0; return std::fmod((double)a, (double)b); } else { null_map[index] = b == 0; return typename NumberTraits::ToInteger::Type(a) % (typename NumberTraits::ToInteger::Type(b) + (b == 0)); } } static inline DecimalV2Value apply(DecimalV2Value a, DecimalV2Value b, NullMap& null_map, size_t index) { null_map[index] = b == DecimalV2Value(0); return a % (b + DecimalV2Value(b == DecimalV2Value(0))); } #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) { // TODO: Support return NULL in the future if (UNLIKELY(b == 0)) { // throw Exception("Division by zero", TStatusCode::VEC_ILLEGAL_DIVISION); memset(c.data(), 0, sizeof(ResultType) * c.size()); return; } #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 = "mod"; }; using FunctionModulo = FunctionBinaryArithmeticToNullType; void register_function_modulo(SimpleFunctionFactory& factory) { factory.register_function(); } } // namespace doris::vectorized