]> git.proxmox.com Git - ceph.git/blame - ceph/src/arrow/cpp/src/gandiva/precompiled/extended_math_ops.cc
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / cpp / src / gandiva / precompiled / extended_math_ops.cc
CommitLineData
1d09f67e
TL
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#ifndef M_PI
19#define M_PI 3.14159265358979323846
20#endif
21
22#include "arrow/util/logging.h"
23#include "gandiva/precompiled/decimal_ops.h"
24
25extern "C" {
26
27#include <math.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include "./types.h"
32
33// Expand the inner fn for types that support extended math.
34#define ENUMERIC_TYPES_UNARY(INNER, OUT_TYPE) \
35 INNER(int32, OUT_TYPE) \
36 INNER(uint32, OUT_TYPE) \
37 INNER(int64, OUT_TYPE) \
38 INNER(uint64, OUT_TYPE) \
39 INNER(float32, OUT_TYPE) \
40 INNER(float64, OUT_TYPE)
41
42// Cubic root
43#define CBRT(IN_TYPE, OUT_TYPE) \
44 FORCE_INLINE \
45 gdv_##OUT_TYPE cbrt_##IN_TYPE(gdv_##IN_TYPE in) { \
46 return static_cast<gdv_float64>(cbrtl(static_cast<long double>(in))); \
47 }
48
49ENUMERIC_TYPES_UNARY(CBRT, float64)
50
51// Exponent
52#define EXP(IN_TYPE, OUT_TYPE) \
53 FORCE_INLINE \
54 gdv_##OUT_TYPE exp_##IN_TYPE(gdv_##IN_TYPE in) { \
55 return static_cast<gdv_float64>(expl(static_cast<long double>(in))); \
56 }
57
58ENUMERIC_TYPES_UNARY(EXP, float64)
59
60// log
61#define LOG(IN_TYPE, OUT_TYPE) \
62 FORCE_INLINE \
63 gdv_##OUT_TYPE log_##IN_TYPE(gdv_##IN_TYPE in) { \
64 return static_cast<gdv_float64>(logl(static_cast<long double>(in))); \
65 }
66
67ENUMERIC_TYPES_UNARY(LOG, float64)
68
69// log base 10
70#define LOG10(IN_TYPE, OUT_TYPE) \
71 FORCE_INLINE \
72 gdv_##OUT_TYPE log10_##IN_TYPE(gdv_##IN_TYPE in) { \
73 return static_cast<gdv_float64>(log10l(static_cast<long double>(in))); \
74 }
75
76#define LOGL(VALUE) static_cast<gdv_float64>(logl(static_cast<long double>(VALUE)))
77
78ENUMERIC_TYPES_UNARY(LOG10, float64)
79
80FORCE_INLINE
81void set_error_for_logbase(int64_t execution_context, double base) {
82 char const* prefix = "divide by zero error with log of base";
83 int size = static_cast<int>(strlen(prefix)) + 64;
84 char* error = reinterpret_cast<char*>(malloc(size));
85 snprintf(error, size, "%s %f", prefix, base);
86 gdv_fn_context_set_error_msg(execution_context, error);
87 free(static_cast<char*>(error));
88}
89
90// log with base
91#define LOG_WITH_BASE(IN_TYPE1, IN_TYPE2, OUT_TYPE) \
92 FORCE_INLINE \
93 gdv_##OUT_TYPE log_##IN_TYPE1##_##IN_TYPE2(gdv_int64 context, gdv_##IN_TYPE1 base, \
94 gdv_##IN_TYPE2 value) { \
95 gdv_##OUT_TYPE log_of_base = LOGL(base); \
96 if (log_of_base == 0) { \
97 set_error_for_logbase(context, static_cast<gdv_float64>(base)); \
98 return 0; \
99 } \
100 return LOGL(value) / LOGL(base); \
101 }
102
103LOG_WITH_BASE(int32, int32, float64)
104LOG_WITH_BASE(uint32, uint32, float64)
105LOG_WITH_BASE(int64, int64, float64)
106LOG_WITH_BASE(uint64, uint64, float64)
107LOG_WITH_BASE(float32, float32, float64)
108LOG_WITH_BASE(float64, float64, float64)
109
110// Sin
111#define SIN(IN_TYPE, OUT_TYPE) \
112 FORCE_INLINE \
113 gdv_##OUT_TYPE sin_##IN_TYPE(gdv_##IN_TYPE in) { \
114 return static_cast<gdv_##OUT_TYPE>(sin(static_cast<long double>(in))); \
115 }
116ENUMERIC_TYPES_UNARY(SIN, float64)
117
118// Asin
119#define ASIN(IN_TYPE, OUT_TYPE) \
120 FORCE_INLINE \
121 gdv_##OUT_TYPE asin_##IN_TYPE(gdv_##IN_TYPE in) { \
122 return static_cast<gdv_##OUT_TYPE>(asin(static_cast<long double>(in))); \
123 }
124ENUMERIC_TYPES_UNARY(ASIN, float64)
125
126// Cos
127#define COS(IN_TYPE, OUT_TYPE) \
128 FORCE_INLINE \
129 gdv_##OUT_TYPE cos_##IN_TYPE(gdv_##IN_TYPE in) { \
130 return static_cast<gdv_##OUT_TYPE>(cos(static_cast<long double>(in))); \
131 }
132ENUMERIC_TYPES_UNARY(COS, float64)
133
134// Acos
135#define ACOS(IN_TYPE, OUT_TYPE) \
136 FORCE_INLINE \
137 gdv_##OUT_TYPE acos_##IN_TYPE(gdv_##IN_TYPE in) { \
138 return static_cast<gdv_##OUT_TYPE>(acos(static_cast<long double>(in))); \
139 }
140ENUMERIC_TYPES_UNARY(ACOS, float64)
141
142// Tan
143#define TAN(IN_TYPE, OUT_TYPE) \
144 FORCE_INLINE \
145 gdv_##OUT_TYPE tan_##IN_TYPE(gdv_##IN_TYPE in) { \
146 return static_cast<gdv_##OUT_TYPE>(tan(static_cast<long double>(in))); \
147 }
148ENUMERIC_TYPES_UNARY(TAN, float64)
149
150// Atan
151#define ATAN(IN_TYPE, OUT_TYPE) \
152 FORCE_INLINE \
153 gdv_##OUT_TYPE atan_##IN_TYPE(gdv_##IN_TYPE in) { \
154 return static_cast<gdv_##OUT_TYPE>(atan(static_cast<long double>(in))); \
155 }
156ENUMERIC_TYPES_UNARY(ATAN, float64)
157
158// Sinh
159#define SINH(IN_TYPE, OUT_TYPE) \
160 FORCE_INLINE \
161 gdv_##OUT_TYPE sinh_##IN_TYPE(gdv_##IN_TYPE in) { \
162 return static_cast<gdv_##OUT_TYPE>(sinh(static_cast<long double>(in))); \
163 }
164ENUMERIC_TYPES_UNARY(SINH, float64)
165
166// Cosh
167#define COSH(IN_TYPE, OUT_TYPE) \
168 FORCE_INLINE \
169 gdv_##OUT_TYPE cosh_##IN_TYPE(gdv_##IN_TYPE in) { \
170 return static_cast<gdv_##OUT_TYPE>(cosh(static_cast<long double>(in))); \
171 }
172ENUMERIC_TYPES_UNARY(COSH, float64)
173
174// Tanh
175#define TANH(IN_TYPE, OUT_TYPE) \
176 FORCE_INLINE \
177 gdv_##OUT_TYPE tanh_##IN_TYPE(gdv_##IN_TYPE in) { \
178 return static_cast<gdv_##OUT_TYPE>(tanh(static_cast<long double>(in))); \
179 }
180ENUMERIC_TYPES_UNARY(TANH, float64)
181
182// Atan2
183#define ATAN2(IN_TYPE, OUT_TYPE) \
184 FORCE_INLINE \
185 gdv_##OUT_TYPE atan2_##IN_TYPE##_##IN_TYPE(gdv_##IN_TYPE in1, gdv_##IN_TYPE in2) { \
186 return static_cast<gdv_##OUT_TYPE>( \
187 atan2(static_cast<long double>(in1), static_cast<long double>(in2))); \
188 }
189ENUMERIC_TYPES_UNARY(ATAN2, float64)
190
191// Cot
192#define COT(IN_TYPE, OUT_TYPE) \
193 FORCE_INLINE \
194 gdv_##OUT_TYPE cot_##IN_TYPE(gdv_##IN_TYPE in) { \
195 return static_cast<gdv_##OUT_TYPE>(tan(M_PI / 2 - static_cast<long double>(in))); \
196 }
197ENUMERIC_TYPES_UNARY(COT, float64)
198
199// Radians
200#define RADIANS(IN_TYPE, OUT_TYPE) \
201 FORCE_INLINE \
202 gdv_##OUT_TYPE radians_##IN_TYPE(gdv_##IN_TYPE in) { \
203 return static_cast<gdv_##OUT_TYPE>(static_cast<long double>(in) * M_PI / 180.0); \
204 }
205ENUMERIC_TYPES_UNARY(RADIANS, float64)
206
207// Degrees
208#define DEGREES(IN_TYPE, OUT_TYPE) \
209 FORCE_INLINE \
210 gdv_##OUT_TYPE degrees_##IN_TYPE(gdv_##IN_TYPE in) { \
211 return static_cast<gdv_##OUT_TYPE>(static_cast<long double>(in) * 180.0 / M_PI); \
212 }
213ENUMERIC_TYPES_UNARY(DEGREES, float64)
214
215// power
216#define POWER(IN_TYPE1, IN_TYPE2, OUT_TYPE) \
217 FORCE_INLINE \
218 gdv_##OUT_TYPE power_##IN_TYPE1##_##IN_TYPE2(gdv_##IN_TYPE1 in1, gdv_##IN_TYPE2 in2) { \
219 return static_cast<gdv_float64>(powl(in1, in2)); \
220 }
221POWER(float64, float64, float64)
222
223FORCE_INLINE
224gdv_int32 round_int32(gdv_int32 num) { return num; }
225
226FORCE_INLINE
227gdv_int64 round_int64(gdv_int64 num) { return num; }
228
229// rounds the number to the nearest integer
230#define ROUND_DECIMAL(TYPE) \
231 FORCE_INLINE \
232 gdv_##TYPE round_##TYPE(gdv_##TYPE num) { \
233 return static_cast<gdv_##TYPE>(trunc(num + ((num >= 0) ? 0.5 : -0.5))); \
234 }
235
236ROUND_DECIMAL(float32)
237ROUND_DECIMAL(float64)
238
239// rounds the number to the given scale
240#define ROUND_DECIMAL_TO_SCALE(TYPE) \
241 FORCE_INLINE \
242 gdv_##TYPE round_##TYPE##_int32(gdv_##TYPE number, gdv_int32 out_scale) { \
243 gdv_float64 scale_multiplier = get_scale_multiplier(out_scale); \
244 return static_cast<gdv_##TYPE>( \
245 trunc(number * scale_multiplier + ((number >= 0) ? 0.5 : -0.5)) / \
246 scale_multiplier); \
247 }
248
249ROUND_DECIMAL_TO_SCALE(float32)
250ROUND_DECIMAL_TO_SCALE(float64)
251
252FORCE_INLINE
253gdv_int32 round_int32_int32(gdv_int32 number, gdv_int32 precision) {
254 // for integers, there is nothing following the decimal point,
255 // so round() always returns the same number if precision >= 0
256 if (precision >= 0) {
257 return number;
258 }
259 gdv_int32 abs_precision = -precision;
260 // This is to ensure that there is no overflow while calculating 10^precision, 9 is
261 // the smallest N for which 10^N does not fit into 32 bits, so we can safely return 0
262 if (abs_precision > 9) {
263 return 0;
264 }
265 gdv_int32 num_sign = (number > 0) ? 1 : -1;
266 gdv_int32 abs_number = number * num_sign;
267 gdv_int32 power_of_10 = static_cast<gdv_int32>(get_power_of_10(abs_precision));
268 gdv_int32 remainder = abs_number % power_of_10;
269 abs_number -= remainder;
270 // if the fractional part of the quotient >= 0.5, round to next higher integer
271 if (remainder >= power_of_10 / 2) {
272 abs_number += power_of_10;
273 }
274 return abs_number * num_sign;
275}
276
277FORCE_INLINE
278gdv_int64 round_int64_int32(gdv_int64 number, gdv_int32 precision) {
279 // for long integers, there is nothing following the decimal point,
280 // so round() always returns the same number if precision >= 0
281 if (precision >= 0) {
282 return number;
283 }
284 gdv_int32 abs_precision = -precision;
285 // This is to ensure that there is no overflow while calculating 10^precision, 19 is
286 // the smallest N for which 10^N does not fit into 64 bits, so we can safely return 0
287 if (abs_precision > 18) {
288 return 0;
289 }
290 gdv_int32 num_sign = (number > 0) ? 1 : -1;
291 gdv_int64 abs_number = number * num_sign;
292 gdv_int64 power_of_10 = get_power_of_10(abs_precision);
293 gdv_int64 remainder = abs_number % power_of_10;
294 abs_number -= remainder;
295 // if the fractional part of the quotient >= 0.5, round to next higher integer
296 if (remainder >= power_of_10 / 2) {
297 abs_number += power_of_10;
298 }
299 return abs_number * num_sign;
300}
301
302FORCE_INLINE
303gdv_int64 get_power_of_10(gdv_int32 exp) {
304 DCHECK_GE(exp, 0);
305 DCHECK_LE(exp, 18);
306 static const gdv_int64 power_of_10[] = {1,
307 10,
308 100,
309 1000,
310 10000,
311 100000,
312 1000000,
313 10000000,
314 100000000,
315 1000000000,
316 10000000000,
317 100000000000,
318 1000000000000,
319 10000000000000,
320 100000000000000,
321 1000000000000000,
322 10000000000000000,
323 100000000000000000,
324 1000000000000000000};
325 return power_of_10[exp];
326}
327
328FORCE_INLINE
329gdv_int64 truncate_int64_int32(gdv_int64 in, gdv_int32 out_scale) {
330 bool overflow = false;
331 arrow::BasicDecimal128 decimal = gandiva::decimalops::FromInt64(in, 38, 0, &overflow);
332 arrow::BasicDecimal128 decimal_with_outscale =
333 gandiva::decimalops::Truncate(gandiva::BasicDecimalScalar128(decimal, 38, 0), 38,
334 out_scale, out_scale, &overflow);
335 if (out_scale < 0) {
336 out_scale = 0;
337 }
338 return gandiva::decimalops::ToInt64(
339 gandiva::BasicDecimalScalar128(decimal_with_outscale, 38, out_scale), &overflow);
340}
341
342FORCE_INLINE
343gdv_float64 get_scale_multiplier(gdv_int32 scale) {
344 static const gdv_float64 values[] = {1.0,
345 10.0,
346 100.0,
347 1000.0,
348 10000.0,
349 100000.0,
350 1000000.0,
351 10000000.0,
352 100000000.0,
353 1000000000.0,
354 10000000000.0,
355 100000000000.0,
356 1000000000000.0,
357 10000000000000.0,
358 100000000000000.0,
359 1000000000000000.0,
360 10000000000000000.0,
361 100000000000000000.0,
362 1000000000000000000.0,
363 10000000000000000000.0};
364 if (scale >= 0 && scale < 20) {
365 return values[scale];
366 }
367 return power_float64_float64(10.0, scale);
368}
369
370// returns the binary representation of a given integer (e.g. 928 -> 1110100000)
371#define BIN_INTEGER(IN_TYPE) \
372 FORCE_INLINE \
373 const char* bin_##IN_TYPE(int64_t context, gdv_##IN_TYPE value, int32_t* out_len) { \
374 *out_len = 0; \
375 int32_t len = 8 * sizeof(value); \
376 char* ret = reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context, len)); \
377 if (ret == nullptr) { \
378 gdv_fn_context_set_error_msg(context, "Could not allocate memory for output"); \
379 return ""; \
380 } \
381 /* handle case when value is zero */ \
382 if (value == 0) { \
383 *out_len = 1; \
384 ret[0] = '0'; \
385 return ret; \
386 } \
387 /* generate binary representation iteratively */ \
388 gdv_u##IN_TYPE i; \
389 int8_t count = 0; \
390 bool first = false; /* flag for not printing left zeros in positive numbers */ \
391 for (i = static_cast<gdv_u##IN_TYPE>(1) << (len - 1); i > 0; i = i / 2) { \
392 if ((value & i) != 0) { \
393 ret[count] = '1'; \
394 if (!first) first = true; \
395 } else { \
396 if (!first) continue; \
397 ret[count] = '0'; \
398 } \
399 count += 1; \
400 } \
401 *out_len = count; \
402 return ret; \
403 }
404
405BIN_INTEGER(int32)
406BIN_INTEGER(int64)
407
408#undef BIN_INTEGER
409
410} // extern "C"