1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* |
10 | * N.J. Nes, M. Kersten |
11 | * 07/01/1996 |
12 | * The math module |
13 | * This module contains the math commands. The implementation is very simply, |
14 | * the c math library functions are called. See for documentation the |
15 | * ANSI-C/POSIX manuals of the equaly named functions. |
16 | * |
17 | * NOTE: the operand itself is being modified, rather than that we produce |
18 | * a new BAT. This to save the expensive copying. |
19 | */ |
20 | #include "monetdb_config.h" |
21 | #include "mmath.h" |
22 | #include <fenv.h> |
23 | #include "mmath_private.h" |
24 | #ifndef FE_INVALID |
25 | #define FE_INVALID 0 |
26 | #endif |
27 | #ifndef FE_DIVBYZERO |
28 | #define FE_DIVBYZERO 0 |
29 | #endif |
30 | #ifndef FE_OVERFLOW |
31 | #define FE_OVERFLOW 0 |
32 | #endif |
33 | |
34 | #define cot(x) (1 / tan(x)) |
35 | #define radians(x) ((x) * 3.14159265358979323846 / 180.0) |
36 | #define degrees(x) ((x) * 180.0 / 3.14159265358979323846) |
37 | |
38 | double |
39 | logbs(double x, double base) |
40 | { |
41 | return log(x) / log(base); |
42 | } |
43 | |
44 | float |
45 | logbsf(float x, float base) |
46 | { |
47 | return logf(x) / logf(base); |
48 | } |
49 | |
50 | #define unopbaseM5(NAME, FUNC, TYPE) \ |
51 | str \ |
52 | MATHunary##NAME##TYPE(TYPE *res , const TYPE *a) \ |
53 | { \ |
54 | if (is_##TYPE##_nil(*a)) { \ |
55 | *res = TYPE##_nil; \ |
56 | } else { \ |
57 | double a1 = *a, r; \ |
58 | int e = 0, ex = 0; \ |
59 | errno = 0; \ |
60 | feclearexcept(FE_ALL_EXCEPT); \ |
61 | r = FUNC(a1); \ |
62 | if ((e = errno) != 0 || \ |
63 | (ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | \ |
64 | FE_OVERFLOW)) != 0) { \ |
65 | const char *err; \ |
66 | if (e) { \ |
67 | err = strerror(e); \ |
68 | } else if (ex & FE_DIVBYZERO) \ |
69 | err = "Divide by zero"; \ |
70 | else if (ex & FE_OVERFLOW) \ |
71 | err = "Overflow"; \ |
72 | else \ |
73 | err = "Invalid result"; \ |
74 | throw(MAL, "mmath." #FUNC, "Math exception: %s", err); \ |
75 | } \ |
76 | *res = (TYPE) r; \ |
77 | } \ |
78 | return MAL_SUCCEED; \ |
79 | } |
80 | |
81 | #define unopM5(NAME, FUNC) \ |
82 | unopbaseM5(NAME, FUNC, dbl) \ |
83 | unopbaseM5(NAME, FUNC, flt) |
84 | |
85 | #define binopbaseM5(NAME, FUNC, TYPE) \ |
86 | str \ |
87 | MATHbinary##NAME##TYPE(TYPE *res, const TYPE *a, const TYPE *b) \ |
88 | { \ |
89 | if (is_##TYPE##_nil(*a) || is_##TYPE##_nil(*b)) { \ |
90 | *res = TYPE##_nil; \ |
91 | } else { \ |
92 | double r1, a1 = *a, b1 = *b; \ |
93 | int e = 0, ex = 0; \ |
94 | errno = 0; \ |
95 | feclearexcept(FE_ALL_EXCEPT); \ |
96 | r1 = FUNC(a1, b1); \ |
97 | if ((e = errno) != 0 || \ |
98 | (ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | \ |
99 | FE_OVERFLOW)) != 0) { \ |
100 | const char *err; \ |
101 | if (e) { \ |
102 | err = strerror(e); \ |
103 | } else if (ex & FE_DIVBYZERO) \ |
104 | err = "Divide by zero"; \ |
105 | else if (ex & FE_OVERFLOW) \ |
106 | err = "Overflow"; \ |
107 | else \ |
108 | err = "Invalid result"; \ |
109 | throw(MAL, "mmath." #FUNC, "Math exception: %s", err); \ |
110 | } \ |
111 | *res= (TYPE) r1; \ |
112 | } \ |
113 | return MAL_SUCCEED; \ |
114 | } |
115 | |
116 | #define unopM5NOT(NAME, FUNC) \ |
117 | str \ |
118 | MATHunary##NAME##dbl(dbl *res , const dbl *a) \ |
119 | { \ |
120 | (void)res; \ |
121 | (void)a; \ |
122 | throw(MAL, "mmath." #FUNC, SQLSTATE(0A000) PROGRAM_NYI); \ |
123 | } \ |
124 | str \ |
125 | MATHunary##NAME##flt(flt *res , const flt *a) \ |
126 | { \ |
127 | (void)res; \ |
128 | (void)a; \ |
129 | throw(MAL, "mmath." #FUNC, SQLSTATE(0A000) PROGRAM_NYI); \ |
130 | } |
131 | |
132 | #define binopM5(NAME, FUNC) \ |
133 | binopbaseM5(NAME, FUNC, dbl) \ |
134 | binopbaseM5(NAME, FUNC, flt) |
135 | |
136 | #define roundM5(TYPE) \ |
137 | str \ |
138 | MATHbinary_ROUND##TYPE(TYPE *res, const TYPE *x, const int *y) \ |
139 | { \ |
140 | if (is_##TYPE##_nil(*x) || is_int_nil(*y)) { \ |
141 | *res = TYPE##_nil; \ |
142 | } else { \ |
143 | dbl factor = pow(10,*y), integral; \ |
144 | dbl tmp = *y > 0 ? modf(*x, &integral) : *x; \ |
145 | \ |
146 | tmp *= factor; \ |
147 | if (tmp >= 0) \ |
148 | tmp = floor(tmp + 0.5); \ |
149 | else \ |
150 | tmp = ceil(tmp - 0.5); \ |
151 | tmp /= factor; \ |
152 | \ |
153 | if (*y > 0) \ |
154 | tmp += integral; \ |
155 | \ |
156 | *res = (TYPE) tmp; \ |
157 | } \ |
158 | return MAL_SUCCEED; \ |
159 | } |
160 | |
161 | |
162 | unopM5(_ACOS,acos) |
163 | unopM5(_ASIN,asin) |
164 | unopM5(_ATAN,atan) |
165 | binopM5(_ATAN2,atan2) |
166 | unopM5(_COS,cos) |
167 | unopM5(_SIN,sin) |
168 | unopM5(_TAN,tan) |
169 | unopM5(_COT,cot) |
170 | unopM5(_RADIANS,radians) |
171 | unopM5(_DEGREES,degrees) |
172 | |
173 | unopM5(_COSH,cosh) |
174 | unopM5(_SINH,sinh) |
175 | unopM5(_TANH,tanh) |
176 | |
177 | unopM5(_EXP,exp) |
178 | unopM5(_LOG,log) |
179 | unopM5(_LOG10,log10) |
180 | unopM5(_LOG2,log2) |
181 | |
182 | binopM5(_LOG,logbs) |
183 | |
184 | binopM5(_POW,pow) |
185 | unopM5(_SQRT,sqrt) |
186 | #ifdef HAVE_CBRT |
187 | unopM5(_CBRT,cbrt) |
188 | #else |
189 | unopM5NOT(_CBRT,cbrt) |
190 | #endif |
191 | |
192 | unopM5(_CEIL,ceil) |
193 | unopM5(_FLOOR,floor) |
194 | |
195 | str |
196 | MATHunary_FABSdbl(dbl *res , const dbl *a) |
197 | { |
198 | *res = is_dbl_nil(*a) ? dbl_nil : fabs(*a); |
199 | return MAL_SUCCEED; |
200 | } |
201 | |
202 | roundM5(dbl) |
203 | roundM5(flt) |
204 | |
205 | str |
206 | MATHunary_ISNAN(bit *res, const dbl *a) |
207 | { |
208 | if (is_dbl_nil(*a)) { |
209 | *res = bit_nil; |
210 | } else { |
211 | *res = isnan(*a) != 0; |
212 | } |
213 | return MAL_SUCCEED; |
214 | } |
215 | |
216 | str |
217 | MATHunary_ISINF(int *res, const dbl *a) |
218 | { |
219 | if (is_dbl_nil(*a)) { |
220 | *res = int_nil; |
221 | } else { |
222 | if (isinf(*a)) { |
223 | *res = (*a < 0.0) ? -1 : 1; |
224 | } else { |
225 | *res = 0; |
226 | } |
227 | } |
228 | return MAL_SUCCEED; |
229 | } |
230 | |
231 | str |
232 | MATHunary_FINITE(bit *res, const dbl *a) |
233 | { |
234 | if (is_dbl_nil(*a)) { |
235 | *res = bit_nil; |
236 | } else { |
237 | *res = isfinite(*a) != 0; |
238 | } |
239 | return MAL_SUCCEED; |
240 | } |
241 | |
242 | #include "xoshiro256starstar.h" |
243 | |
244 | /* global pseudo random generator state */ |
245 | static random_state_engine mmath_rse; |
246 | /* serialize access to state */ |
247 | static MT_Lock mmath_rse_lock = MT_LOCK_INITIALIZER("mmath_rse_lock" ); |
248 | |
249 | str |
250 | MATHprelude(void *ret) |
251 | { |
252 | (void) ret; |
253 | init_random_state_engine(mmath_rse, (uint64_t) GDKusec()); |
254 | return MAL_SUCCEED; |
255 | } |
256 | |
257 | str |
258 | MATHrandint(int *res) |
259 | { |
260 | #ifdef STATIC_CODE_ANALYSIS |
261 | *res = 0; |
262 | #else |
263 | MT_lock_set(&mmath_rse_lock); |
264 | *res = (int) (next(mmath_rse) >> 33); |
265 | MT_lock_unset(&mmath_rse_lock); |
266 | #endif |
267 | return MAL_SUCCEED; |
268 | } |
269 | |
270 | str |
271 | MATHrandintarg(int *res, const int *dummy) |
272 | { |
273 | (void) dummy; |
274 | #ifdef STATIC_CODE_ANALYSIS |
275 | *res = 0; |
276 | #else |
277 | MT_lock_set(&mmath_rse_lock); |
278 | *res = (int) (next(mmath_rse) >> 33); |
279 | MT_lock_unset(&mmath_rse_lock); |
280 | #endif |
281 | return MAL_SUCCEED; |
282 | } |
283 | |
284 | str |
285 | MATHsrandint(void *ret, const int *seed) |
286 | { |
287 | (void) ret; |
288 | MT_lock_set(&mmath_rse_lock); |
289 | init_random_state_engine(mmath_rse, (uint64_t) *seed); |
290 | MT_lock_unset(&mmath_rse_lock); |
291 | return MAL_SUCCEED; |
292 | } |
293 | |
294 | str |
295 | MATHsqlrandint(int *res, const int *seed) |
296 | { |
297 | #ifdef STATIC_CODE_ANALYSIS |
298 | *res = 0; |
299 | #else |
300 | MT_lock_set(&mmath_rse_lock); |
301 | init_random_state_engine(mmath_rse, (uint64_t) *seed); |
302 | *res = (int) (next(mmath_rse) >> 33); |
303 | MT_lock_unset(&mmath_rse_lock); |
304 | #endif |
305 | return MAL_SUCCEED; |
306 | } |
307 | |
308 | str |
309 | MATHpi(dbl *pi) |
310 | { |
311 | *pi = 3.14159265358979323846; |
312 | return MAL_SUCCEED; |
313 | } |
314 | |
315 | |