1#pragma once
2
3#include <Core/callOnTypeIndex.h>
4#include <DataTypes/DataTypesNumber.h>
5#include <DataTypes/DataTypesDecimal.h>
6#include <Columns/ColumnsNumber.h>
7#include <Columns/ColumnDecimal.h>
8#include <Columns/ColumnConst.h>
9#include <Functions/IFunctionImpl.h>
10#include <Functions/FunctionHelpers.h>
11#include "config_functions.h"
12
13/** More efficient implementations of mathematical functions are possible when using a separate library.
14 * Disabled due to license compatibility limitations.
15 * To enable: download http://www.agner.org/optimize/vectorclass.zip and unpack to contrib/vectorclass
16 * Then rebuild with -DENABLE_VECTORCLASS=1
17 */
18
19#if USE_VECTORCLASS
20 #ifdef __clang__
21 #pragma clang diagnostic push
22 #pragma clang diagnostic ignored "-Wshift-negative-value"
23 #endif
24
25 #include <vectorf128.h>
26 #include <vectormath_exp.h>
27
28 #ifdef __clang__
29 #pragma clang diagnostic pop
30 #endif
31#endif
32
33
34namespace DB
35{
36
37namespace ErrorCodes
38{
39 extern const int ILLEGAL_COLUMN;
40}
41
42
43template <typename Impl>
44class FunctionMathBinaryFloat64 : public IFunction
45{
46public:
47 static constexpr auto name = Impl::name;
48 static FunctionPtr create(const Context &) { return std::make_shared<FunctionMathBinaryFloat64>(); }
49 static_assert(Impl::rows_per_iteration > 0, "Impl must process at least one row per iteration");
50
51 bool useDefaultImplementationForConstants() const override { return true; }
52
53private:
54 String getName() const override { return name; }
55
56 size_t getNumberOfArguments() const override { return 2; }
57
58 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
59 {
60 const auto check_argument_type = [this] (const IDataType * arg)
61 {
62 if (!isNativeNumber(arg))
63 throw Exception{"Illegal type " + arg->getName() + " of argument of function " + getName(),
64 ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
65 };
66
67 check_argument_type(arguments.front().get());
68 check_argument_type(arguments.back().get());
69
70 return std::make_shared<DataTypeFloat64>();
71 }
72
73 template <typename LeftType, typename RightType>
74 bool executeTyped(Block & block, const size_t result, const ColumnConst * left_arg, const IColumn * right_arg)
75 {
76 if (const auto right_arg_typed = checkAndGetColumn<ColumnVector<RightType>>(right_arg))
77 {
78 auto dst = ColumnVector<Float64>::create();
79
80 LeftType left_src_data[Impl::rows_per_iteration];
81 std::fill(std::begin(left_src_data), std::end(left_src_data), left_arg->template getValue<LeftType>());
82 const auto & right_src_data = right_arg_typed->getData();
83 const auto src_size = right_src_data.size();
84 auto & dst_data = dst->getData();
85 dst_data.resize(src_size);
86
87 const auto rows_remaining = src_size % Impl::rows_per_iteration;
88 const auto rows_size = src_size - rows_remaining;
89
90 for (size_t i = 0; i < rows_size; i += Impl::rows_per_iteration)
91 Impl::execute(left_src_data, &right_src_data[i], &dst_data[i]);
92
93 if (rows_remaining != 0)
94 {
95 RightType right_src_remaining[Impl::rows_per_iteration];
96 memcpy(right_src_remaining, &right_src_data[rows_size], rows_remaining * sizeof(RightType));
97 memset(right_src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(RightType));
98 Float64 dst_remaining[Impl::rows_per_iteration];
99
100 Impl::execute(left_src_data, right_src_remaining, dst_remaining);
101
102 memcpy(&dst_data[rows_size], dst_remaining, rows_remaining * sizeof(Float64));
103 }
104
105 block.getByPosition(result).column = std::move(dst);
106 return true;
107 }
108
109 return false;
110 }
111
112 template <typename LeftType, typename RightType>
113 bool executeTyped(Block & block, const size_t result, const ColumnVector<LeftType> * left_arg, const IColumn * right_arg)
114 {
115 if (const auto right_arg_typed = checkAndGetColumn<ColumnVector<RightType>>(right_arg))
116 {
117 auto dst = ColumnVector<Float64>::create();
118
119 const auto & left_src_data = left_arg->getData();
120 const auto & right_src_data = right_arg_typed->getData();
121 const auto src_size = left_src_data.size();
122 auto & dst_data = dst->getData();
123 dst_data.resize(src_size);
124
125 const auto rows_remaining = src_size % Impl::rows_per_iteration;
126 const auto rows_size = src_size - rows_remaining;
127
128 for (size_t i = 0; i < rows_size; i += Impl::rows_per_iteration)
129 Impl::execute(&left_src_data[i], &right_src_data[i], &dst_data[i]);
130
131 if (rows_remaining != 0)
132 {
133 LeftType left_src_remaining[Impl::rows_per_iteration];
134 memcpy(left_src_remaining, &left_src_data[rows_size], rows_remaining * sizeof(LeftType));
135 memset(left_src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(LeftType));
136 RightType right_src_remaining[Impl::rows_per_iteration];
137 memcpy(right_src_remaining, &right_src_data[rows_size], rows_remaining * sizeof(RightType));
138 memset(right_src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(RightType));
139 Float64 dst_remaining[Impl::rows_per_iteration];
140
141 Impl::execute(left_src_remaining, right_src_remaining, dst_remaining);
142
143 memcpy(&dst_data[rows_size], dst_remaining, rows_remaining * sizeof(Float64));
144 }
145
146 block.getByPosition(result).column = std::move(dst);
147 return true;
148 }
149 if (const auto right_arg_typed = checkAndGetColumnConst<ColumnVector<RightType>>(right_arg))
150 {
151 auto dst = ColumnVector<Float64>::create();
152
153 const auto & left_src_data = left_arg->getData();
154 RightType right_src_data[Impl::rows_per_iteration];
155 std::fill(std::begin(right_src_data), std::end(right_src_data), right_arg_typed->template getValue<RightType>());
156 const auto src_size = left_src_data.size();
157 auto & dst_data = dst->getData();
158 dst_data.resize(src_size);
159
160 const auto rows_remaining = src_size % Impl::rows_per_iteration;
161 const auto rows_size = src_size - rows_remaining;
162
163 for (size_t i = 0; i < rows_size; i += Impl::rows_per_iteration)
164 Impl::execute(&left_src_data[i], right_src_data, &dst_data[i]);
165
166 if (rows_remaining != 0)
167 {
168 LeftType left_src_remaining[Impl::rows_per_iteration];
169 memcpy(left_src_remaining, &left_src_data[rows_size], rows_remaining * sizeof(LeftType));
170 memset(left_src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(LeftType));
171 Float64 dst_remaining[Impl::rows_per_iteration];
172
173 Impl::execute(left_src_remaining, right_src_data, dst_remaining);
174
175 memcpy(&dst_data[rows_size], dst_remaining, rows_remaining * sizeof(Float64));
176 }
177
178 block.getByPosition(result).column = std::move(dst);
179 return true;
180 }
181
182 return false;
183 }
184
185 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
186 {
187 const ColumnWithTypeAndName & col_left = block.getByPosition(arguments[0]);
188 const ColumnWithTypeAndName & col_right = block.getByPosition(arguments[1]);
189
190 auto call = [&](const auto & types) -> bool
191 {
192 using Types = std::decay_t<decltype(types)>;
193 using LeftType = typename Types::LeftType;
194 using RightType = typename Types::RightType;
195 using ColVecLeft = ColumnVector<LeftType>;
196
197 const IColumn * left_arg = col_left.column.get();
198 const IColumn * right_arg = col_right.column.get();
199
200 if (const auto left_arg_typed = checkAndGetColumn<ColVecLeft>(left_arg))
201 {
202 if (executeTyped<LeftType, RightType>(block, result, left_arg_typed, right_arg))
203 return true;
204
205 throw Exception{"Illegal column " + right_arg->getName() + " of second argument of function " + getName(),
206 ErrorCodes::ILLEGAL_COLUMN};
207 }
208 if (const auto left_arg_typed = checkAndGetColumnConst<ColVecLeft>(left_arg))
209 {
210 if (executeTyped<LeftType, RightType>(block, result, left_arg_typed, right_arg))
211 return true;
212
213 throw Exception{"Illegal column " + right_arg->getName() + " of second argument of function " + getName(),
214 ErrorCodes::ILLEGAL_COLUMN};
215 }
216
217 return false;
218 };
219
220 TypeIndex left_index = col_left.type->getTypeId();
221 TypeIndex right_index = col_right.type->getTypeId();
222
223 if (!callOnBasicTypes<true, true, false, false>(left_index, right_index, call))
224 throw Exception{"Illegal column " + col_left.column->getName() + " of argument of function " + getName(),
225 ErrorCodes::ILLEGAL_COLUMN};
226 }
227};
228
229
230template <typename Name, Float64(Function)(Float64, Float64)>
231struct BinaryFunctionPlain
232{
233 static constexpr auto name = Name::name;
234 static constexpr auto rows_per_iteration = 1;
235
236 template <typename T1, typename T2>
237 static void execute(const T1 * src_left, const T2 * src_right, Float64 * dst)
238 {
239 dst[0] = static_cast<Float64>(Function(static_cast<Float64>(src_left[0]), static_cast<Float64>(src_right[0])));
240 }
241};
242
243#if USE_VECTORCLASS
244
245template <typename Name, Vec2d(Function)(const Vec2d &, const Vec2d &)>
246struct BinaryFunctionVectorized
247{
248 static constexpr auto name = Name::name;
249 static constexpr auto rows_per_iteration = 2;
250
251 template <typename T1, typename T2>
252 static void execute(const T1 * src_left, const T2 * src_right, Float64 * dst)
253 {
254 const auto result = Function(Vec2d(src_left[0], src_left[1]), Vec2d(src_right[0], src_right[1]));
255 result.store(dst);
256 }
257};
258
259#else
260
261#define BinaryFunctionVectorized BinaryFunctionPlain
262
263#endif
264
265}
266