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 | |
42 | namespace DB |
43 | { |
44 | |
45 | namespace ErrorCodes |
46 | { |
47 | extern const int ILLEGAL_COLUMN; |
48 | } |
49 | |
50 | |
51 | template <typename Impl> |
52 | class FunctionMathUnary : public IFunction |
53 | { |
54 | public: |
55 | static constexpr auto name = Impl::name; |
56 | static FunctionPtr create(const Context &) { return std::make_shared<FunctionMathUnary>(); } |
57 | |
58 | private: |
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 | |
179 | template <typename Name, Float64(Function)(Float64)> |
180 | struct 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 | |
195 | template <typename Name, Vec2d(Function)(const Vec2d &)> |
196 | struct 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 | |