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 <Functions/IFunctionImpl.h>
9#include <Functions/FunctionHelpers.h>
10#include "config_functions.h"
11
12/** More efficient implementations of mathematical functions are possible when using a separate library.
13 * Disabled due to license compatibility limitations.
14 * To enable: download http://www.agner.org/optimize/vectorclass.zip and unpack to contrib/vectorclass
15 * Then rebuild with -DENABLE_VECTORCLASS=1
16 */
17
18#if USE_VECTORCLASS
19 #ifdef __clang__
20 #pragma clang diagnostic push
21 #pragma clang diagnostic ignored "-Wshift-negative-value"
22 #endif
23
24 #include <vectorf128.h>
25 #include <vectormath_exp.h>
26 #include <vectormath_trig.h>
27
28 #ifdef __clang__
29 #pragma clang diagnostic pop
30 #endif
31#endif
32
33
34/** FastOps is a fast vector math library from Mikhail Parakhin (former Yandex CTO),
35 * Enabled by default.
36 */
37#if USE_FASTOPS
38#include <fastops/fastops.h>
39#endif
40
41
42namespace DB
43{
44
45namespace ErrorCodes
46{
47 extern const int ILLEGAL_COLUMN;
48}
49
50
51template <typename Impl>
52class FunctionMathUnary : public IFunction
53{
54public:
55 static constexpr auto name = Impl::name;
56 static FunctionPtr create(const Context &) { return std::make_shared<FunctionMathUnary>(); }
57
58private:
59 String getName() const override { return name; }
60 size_t getNumberOfArguments() const override { return 1; }
61
62 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
63 {
64 const auto & arg = arguments.front();
65 if (!isNumber(arg))
66 throw Exception{"Illegal type " + arg->getName() + " of argument of function " + getName(),
67 ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
68
69 /// Integers are converted to Float64.
70 if (Impl::always_returns_float64 || !isFloat(arg))
71 return std::make_shared<DataTypeFloat64>();
72 else
73 return arg;
74 }
75
76 template <typename T, typename ReturnType>
77 static void executeInIterations(const T * src_data, ReturnType * dst_data, size_t size)
78 {
79 if constexpr (Impl::rows_per_iteration == 0)
80 {
81 /// Process all data as a whole and use FastOps implementation
82
83 /// If the argument is integer, convert to Float64 beforehand
84 if constexpr (!std::is_floating_point_v<T>)
85 {
86 PODArray<Float64> tmp_vec(size);
87 for (size_t i = 0; i < size; ++i)
88 tmp_vec[i] = src_data[i];
89
90 Impl::execute(tmp_vec.data(), size, dst_data);
91 }
92 else
93 {
94 Impl::execute(src_data, size, dst_data);
95 }
96 }
97 else
98 {
99 const size_t rows_remaining = size % Impl::rows_per_iteration;
100 const size_t rows_size = size - rows_remaining;
101
102 for (size_t i = 0; i < rows_size; i += Impl::rows_per_iteration)
103 Impl::execute(&src_data[i], &dst_data[i]);
104
105 if (rows_remaining != 0)
106 {
107 T src_remaining[Impl::rows_per_iteration];
108 memcpy(src_remaining, &src_data[rows_size], rows_remaining * sizeof(T));
109 memset(src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(T));
110 ReturnType dst_remaining[Impl::rows_per_iteration];
111
112 Impl::execute(src_remaining, dst_remaining);
113
114 memcpy(&dst_data[rows_size], dst_remaining, rows_remaining * sizeof(ReturnType));
115 }
116 }
117 }
118
119 template <typename T, typename ReturnType>
120 static bool execute(Block & block, const ColumnVector<T> * col, const size_t result)
121 {
122 const auto & src_data = col->getData();
123 const size_t size = src_data.size();
124
125 auto dst = ColumnVector<ReturnType>::create();
126 auto & dst_data = dst->getData();
127 dst_data.resize(size);
128
129 executeInIterations(src_data.data(), dst_data.data(), size);
130
131 block.getByPosition(result).column = std::move(dst);
132 return true;
133 }
134
135 template <typename T, typename ReturnType>
136 static bool execute(Block & block, const ColumnDecimal<T> * col, const size_t result)
137 {
138 const auto & src_data = col->getData();
139 const size_t size = src_data.size();
140 UInt32 scale = src_data.getScale();
141
142 auto dst = ColumnVector<ReturnType>::create();
143 auto & dst_data = dst->getData();
144 dst_data.resize(size);
145
146 for (size_t i = 0; i < size; ++i)
147 dst_data[i] = convertFromDecimal<DataTypeDecimal<T>, DataTypeNumber<ReturnType>>(src_data[i], scale);
148
149 executeInIterations(dst_data.data(), dst_data.data(), size);
150
151 block.getByPosition(result).column = std::move(dst);
152 return true;
153 }
154
155 bool useDefaultImplementationForConstants() const override { return true; }
156
157 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
158 {
159 const ColumnWithTypeAndName & col = block.getByPosition(arguments[0]);
160
161 auto call = [&](const auto & types) -> bool
162 {
163 using Types = std::decay_t<decltype(types)>;
164 using Type = typename Types::RightType;
165 using ReturnType = std::conditional_t<Impl::always_returns_float64 || !std::is_floating_point_v<Type>, Float64, Type>;
166 using ColVecType = std::conditional_t<IsDecimalNumber<Type>, ColumnDecimal<Type>, ColumnVector<Type>>;
167
168 const auto col_vec = checkAndGetColumn<ColVecType>(col.column.get());
169 return execute<Type, ReturnType>(block, col_vec, result);
170 };
171
172 if (!callOnBasicType<void, true, true, true, false>(col.type->getTypeId(), call))
173 throw Exception{"Illegal column " + col.column->getName() + " of argument of function " + getName(),
174 ErrorCodes::ILLEGAL_COLUMN};
175 }
176};
177
178
179template <typename Name, Float64(Function)(Float64)>
180struct UnaryFunctionPlain
181{
182 static constexpr auto name = Name::name;
183 static constexpr auto rows_per_iteration = 1;
184 static constexpr bool always_returns_float64 = true;
185
186 template <typename T>
187 static void execute(const T * src, Float64 * dst)
188 {
189 dst[0] = static_cast<Float64>(Function(static_cast<Float64>(src[0])));
190 }
191};
192
193#if USE_VECTORCLASS
194
195template <typename Name, Vec2d(Function)(const Vec2d &)>
196struct UnaryFunctionVectorized
197{
198 static constexpr auto name = Name::name;
199 static constexpr auto rows_per_iteration = 2;
200 static constexpr bool always_returns_float64 = true;
201
202 template <typename T>
203 static void execute(const T * src, Float64 * dst)
204 {
205 const auto result = Function(Vec2d(src[0], src[1]));
206 result.store(dst);
207 }
208};
209
210#else
211
212#define UnaryFunctionVectorized UnaryFunctionPlain
213
214#endif
215
216}
217