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
9 // http://www.apache.org/licenses/LICENSE-2.0
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
19 #define M_PI 3.14159265358979323846
22 #include "arrow/util/logging.h"
23 #include "gandiva/precompiled/decimal_ops.h"
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)
43 #define CBRT(IN_TYPE, OUT_TYPE) \
45 gdv_##OUT_TYPE cbrt_##IN_TYPE(gdv_##IN_TYPE in) { \
46 return static_cast<gdv_float64>(cbrtl(static_cast<long double>(in))); \
49 ENUMERIC_TYPES_UNARY(CBRT
, float64
)
52 #define EXP(IN_TYPE, OUT_TYPE) \
54 gdv_##OUT_TYPE exp_##IN_TYPE(gdv_##IN_TYPE in) { \
55 return static_cast<gdv_float64>(expl(static_cast<long double>(in))); \
58 ENUMERIC_TYPES_UNARY(EXP
, float64
)
61 #define LOG(IN_TYPE, OUT_TYPE) \
63 gdv_##OUT_TYPE log_##IN_TYPE(gdv_##IN_TYPE in) { \
64 return static_cast<gdv_float64>(logl(static_cast<long double>(in))); \
67 ENUMERIC_TYPES_UNARY(LOG
, float64
)
70 #define LOG10(IN_TYPE, OUT_TYPE) \
72 gdv_##OUT_TYPE log10_##IN_TYPE(gdv_##IN_TYPE in) { \
73 return static_cast<gdv_float64>(log10l(static_cast<long double>(in))); \
76 #define LOGL(VALUE) static_cast<gdv_float64>(logl(static_cast<long double>(VALUE)))
78 ENUMERIC_TYPES_UNARY(LOG10
, float64
)
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
));
91 #define LOG_WITH_BASE(IN_TYPE1, IN_TYPE2, OUT_TYPE) \
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)); \
100 return LOGL(value) / LOGL(base); \
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
)
111 #define SIN(IN_TYPE, OUT_TYPE) \
113 gdv_##OUT_TYPE sin_##IN_TYPE(gdv_##IN_TYPE in) { \
114 return static_cast<gdv_##OUT_TYPE>(sin(static_cast<long double>(in))); \
116 ENUMERIC_TYPES_UNARY(SIN
, float64
)
119 #define ASIN(IN_TYPE, OUT_TYPE) \
121 gdv_##OUT_TYPE asin_##IN_TYPE(gdv_##IN_TYPE in) { \
122 return static_cast<gdv_##OUT_TYPE>(asin(static_cast<long double>(in))); \
124 ENUMERIC_TYPES_UNARY(ASIN
, float64
)
127 #define COS(IN_TYPE, OUT_TYPE) \
129 gdv_##OUT_TYPE cos_##IN_TYPE(gdv_##IN_TYPE in) { \
130 return static_cast<gdv_##OUT_TYPE>(cos(static_cast<long double>(in))); \
132 ENUMERIC_TYPES_UNARY(COS
, float64
)
135 #define ACOS(IN_TYPE, OUT_TYPE) \
137 gdv_##OUT_TYPE acos_##IN_TYPE(gdv_##IN_TYPE in) { \
138 return static_cast<gdv_##OUT_TYPE>(acos(static_cast<long double>(in))); \
140 ENUMERIC_TYPES_UNARY(ACOS
, float64
)
143 #define TAN(IN_TYPE, OUT_TYPE) \
145 gdv_##OUT_TYPE tan_##IN_TYPE(gdv_##IN_TYPE in) { \
146 return static_cast<gdv_##OUT_TYPE>(tan(static_cast<long double>(in))); \
148 ENUMERIC_TYPES_UNARY(TAN
, float64
)
151 #define ATAN(IN_TYPE, OUT_TYPE) \
153 gdv_##OUT_TYPE atan_##IN_TYPE(gdv_##IN_TYPE in) { \
154 return static_cast<gdv_##OUT_TYPE>(atan(static_cast<long double>(in))); \
156 ENUMERIC_TYPES_UNARY(ATAN
, float64
)
159 #define SINH(IN_TYPE, OUT_TYPE) \
161 gdv_##OUT_TYPE sinh_##IN_TYPE(gdv_##IN_TYPE in) { \
162 return static_cast<gdv_##OUT_TYPE>(sinh(static_cast<long double>(in))); \
164 ENUMERIC_TYPES_UNARY(SINH
, float64
)
167 #define COSH(IN_TYPE, OUT_TYPE) \
169 gdv_##OUT_TYPE cosh_##IN_TYPE(gdv_##IN_TYPE in) { \
170 return static_cast<gdv_##OUT_TYPE>(cosh(static_cast<long double>(in))); \
172 ENUMERIC_TYPES_UNARY(COSH
, float64
)
175 #define TANH(IN_TYPE, OUT_TYPE) \
177 gdv_##OUT_TYPE tanh_##IN_TYPE(gdv_##IN_TYPE in) { \
178 return static_cast<gdv_##OUT_TYPE>(tanh(static_cast<long double>(in))); \
180 ENUMERIC_TYPES_UNARY(TANH
, float64
)
183 #define ATAN2(IN_TYPE, OUT_TYPE) \
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))); \
189 ENUMERIC_TYPES_UNARY(ATAN2
, float64
)
192 #define COT(IN_TYPE, OUT_TYPE) \
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))); \
197 ENUMERIC_TYPES_UNARY(COT
, float64
)
200 #define RADIANS(IN_TYPE, OUT_TYPE) \
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); \
205 ENUMERIC_TYPES_UNARY(RADIANS
, float64
)
208 #define DEGREES(IN_TYPE, OUT_TYPE) \
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); \
213 ENUMERIC_TYPES_UNARY(DEGREES
, float64
)
216 #define POWER(IN_TYPE1, IN_TYPE2, OUT_TYPE) \
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)); \
221 POWER(float64
, float64
, float64
)
224 gdv_int32
round_int32(gdv_int32 num
) { return num
; }
227 gdv_int64
round_int64(gdv_int64 num
) { return num
; }
229 // rounds the number to the nearest integer
230 #define ROUND_DECIMAL(TYPE) \
232 gdv_##TYPE round_##TYPE(gdv_##TYPE num) { \
233 return static_cast<gdv_##TYPE>(trunc(num + ((num >= 0) ? 0.5 : -0.5))); \
236 ROUND_DECIMAL(float32
)
237 ROUND_DECIMAL(float64
)
239 // rounds the number to the given scale
240 #define ROUND_DECIMAL_TO_SCALE(TYPE) \
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)) / \
249 ROUND_DECIMAL_TO_SCALE(float32
)
250 ROUND_DECIMAL_TO_SCALE(float64
)
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) {
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) {
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
;
274 return abs_number
* num_sign
;
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) {
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) {
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
;
299 return abs_number
* num_sign
;
303 gdv_int64
get_power_of_10(gdv_int32 exp
) {
306 static const gdv_int64 power_of_10
[] = {1,
324 1000000000000000000};
325 return power_of_10
[exp
];
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
);
338 return gandiva::decimalops::ToInt64(
339 gandiva::BasicDecimalScalar128(decimal_with_outscale
, 38, out_scale
), &overflow
);
343 gdv_float64
get_scale_multiplier(gdv_int32 scale
) {
344 static const gdv_float64 values
[] = {1.0,
361 100000000000000000.0,
362 1000000000000000000.0,
363 10000000000000000000.0};
364 if (scale
>= 0 && scale
< 20) {
365 return values
[scale
];
367 return power_float64_float64(10.0, scale
);
370 // returns the binary representation of a given integer (e.g. 928 -> 1110100000)
371 #define BIN_INTEGER(IN_TYPE) \
373 const char* bin_##IN_TYPE(int64_t context, gdv_##IN_TYPE value, int32_t* out_len) { \
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"); \
381 /* handle case when value is zero */ \
387 /* generate binary representation iteratively */ \
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) { \
394 if (!first) first = true; \
396 if (!first) continue; \