]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | extern "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 | ||
49 | ENUMERIC_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 | ||
58 | ENUMERIC_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 | ||
67 | ENUMERIC_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 | ||
78 | ENUMERIC_TYPES_UNARY(LOG10, float64) | |
79 | ||
80 | FORCE_INLINE | |
81 | void 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 | ||
103 | LOG_WITH_BASE(int32, int32, float64) | |
104 | LOG_WITH_BASE(uint32, uint32, float64) | |
105 | LOG_WITH_BASE(int64, int64, float64) | |
106 | LOG_WITH_BASE(uint64, uint64, float64) | |
107 | LOG_WITH_BASE(float32, float32, float64) | |
108 | LOG_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 | } | |
116 | ENUMERIC_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 | } | |
124 | ENUMERIC_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 | } | |
132 | ENUMERIC_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 | } | |
140 | ENUMERIC_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 | } | |
148 | ENUMERIC_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 | } | |
156 | ENUMERIC_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 | } | |
164 | ENUMERIC_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 | } | |
172 | ENUMERIC_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 | } | |
180 | ENUMERIC_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 | } | |
189 | ENUMERIC_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 | } | |
197 | ENUMERIC_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 | } | |
205 | ENUMERIC_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 | } | |
213 | ENUMERIC_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 | } | |
221 | POWER(float64, float64, float64) | |
222 | ||
223 | FORCE_INLINE | |
224 | gdv_int32 round_int32(gdv_int32 num) { return num; } | |
225 | ||
226 | FORCE_INLINE | |
227 | gdv_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 | ||
236 | ROUND_DECIMAL(float32) | |
237 | ROUND_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 | ||
249 | ROUND_DECIMAL_TO_SCALE(float32) | |
250 | ROUND_DECIMAL_TO_SCALE(float64) | |
251 | ||
252 | FORCE_INLINE | |
253 | gdv_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 | ||
277 | FORCE_INLINE | |
278 | gdv_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 | ||
302 | FORCE_INLINE | |
303 | gdv_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 | ||
328 | FORCE_INLINE | |
329 | gdv_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 | ||
342 | FORCE_INLINE | |
343 | gdv_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 | ||
405 | BIN_INTEGER(int32) | |
406 | BIN_INTEGER(int64) | |
407 | ||
408 | #undef BIN_INTEGER | |
409 | ||
410 | } // extern "C" |