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 | * M.L. Kersten |
11 | * BAT math calculator |
12 | * This module contains the multiplex versions of the linked |
13 | * in mathematical functions. |
14 | * Scientific routines |
15 | * The mmath functions are also overloaded to provide for |
16 | * the fast execution of expanded code blocks. |
17 | * The common set of math functions is supported. |
18 | */ |
19 | #include "monetdb_config.h" |
20 | #include "batmmath.h" |
21 | #include "gdk_cand.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 voidresultBAT(X1,X2) \ |
35 | do { \ |
36 | bn = COLnew(b->hseqbase, X1, BATcount(b), TRANSIENT); \ |
37 | if (bn == NULL) { \ |
38 | BBPunfix(b->batCacheid); \ |
39 | throw(MAL, X2, SQLSTATE(HY001) MAL_MALLOC_FAIL); \ |
40 | } \ |
41 | bn->tsorted = b->tsorted; \ |
42 | bn->trevsorted = b->trevsorted; \ |
43 | bn->tnonil = b->tnonil; \ |
44 | } while (0) |
45 | |
46 | |
47 | #define scienceFcnImpl(FUNC,TYPE,SUFF) \ |
48 | str CMDscience_bat_##TYPE##_##FUNC##_cand(bat *ret, const bat *bid, const bat *sid) \ |
49 | { \ |
50 | BAT *b, *s = NULL, *bn; \ |
51 | BUN i, cnt; \ |
52 | struct canditer ci; \ |
53 | oid x; \ |
54 | BUN nils = 0; \ |
55 | int e = 0, ex = 0; \ |
56 | \ |
57 | if ((b = BATdescriptor(*bid)) == NULL) { \ |
58 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
59 | } \ |
60 | if (sid != NULL && !is_bat_nil(*sid) && \ |
61 | (s = BATdescriptor(*sid)) == NULL) { \ |
62 | BBPunfix(b->batCacheid); \ |
63 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
64 | } \ |
65 | canditer_init(&ci, b, s); \ |
66 | cnt = BATcount(b); \ |
67 | bn = COLnew(b->hseqbase, TYPE_##TYPE, cnt, TRANSIENT); \ |
68 | if (bn == NULL) { \ |
69 | BBPunfix(b->batCacheid); \ |
70 | BBPunfix(s->batCacheid); \ |
71 | throw(MAL, "batcalc." #FUNC, SQLSTATE(HY001) MAL_MALLOC_FAIL); \ |
72 | } \ |
73 | \ |
74 | const TYPE *restrict src = (const TYPE *) Tloc(b, 0); \ |
75 | TYPE *restrict dst = (TYPE *) Tloc(bn, 0); \ |
76 | errno = 0; \ |
77 | feclearexcept(FE_ALL_EXCEPT); \ |
78 | for (i = 0; i < cnt; i++) { \ |
79 | x = canditer_next(&ci); \ |
80 | if (is_oid_nil(x)) \ |
81 | break; \ |
82 | x -= b->hseqbase; \ |
83 | while (i < x) { \ |
84 | dst[i++] = TYPE##_nil; \ |
85 | nils++; \ |
86 | } \ |
87 | if (is_##TYPE##_nil(src[i])) { \ |
88 | nils++; \ |
89 | dst[i] = TYPE##_nil; \ |
90 | } else { \ |
91 | dst[i] = FUNC##SUFF(src[i]); \ |
92 | } \ |
93 | } \ |
94 | while (i < cnt) { \ |
95 | dst[i++] = TYPE##_nil; \ |
96 | nils++; \ |
97 | } \ |
98 | e = errno; \ |
99 | ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); \ |
100 | BBPunfix(b->batCacheid); \ |
101 | if (s) \ |
102 | BBPunfix(s->batCacheid); \ |
103 | if (e != 0 || ex != 0) { \ |
104 | const char *err; \ |
105 | BBPunfix(bn->batCacheid); \ |
106 | if (e) \ |
107 | err = strerror(e); \ |
108 | else if (ex & FE_DIVBYZERO) \ |
109 | err = "Divide by zero"; \ |
110 | else if (ex & FE_OVERFLOW) \ |
111 | err = "Overflow"; \ |
112 | else \ |
113 | err = "Invalid result"; \ |
114 | throw(MAL, "batmmath." #FUNC, "Math exception: %s", err); \ |
115 | } \ |
116 | BATsetcount(bn, cnt); \ |
117 | bn->theap.dirty = true; \ |
118 | \ |
119 | bn->tsorted = false; \ |
120 | bn->trevsorted = false; \ |
121 | bn->tnil = nils != 0; \ |
122 | bn->tnonil = nils == 0; \ |
123 | BATkey(bn, false); \ |
124 | BBPkeepref(*ret = bn->batCacheid); \ |
125 | return MAL_SUCCEED; \ |
126 | } \ |
127 | \ |
128 | str CMDscience_bat_##TYPE##_##FUNC(bat *ret, const bat *bid) \ |
129 | { \ |
130 | return CMDscience_bat_##TYPE##_##FUNC##_cand(ret, bid, NULL); \ |
131 | } |
132 | |
133 | #define scienceBinaryImpl(FUNC,TYPE,SUFF) \ |
134 | str CMDscience_bat_cst_##FUNC##_##TYPE##_cand(bat *ret, const bat *bid, \ |
135 | const TYPE *d, const bat *sid) \ |
136 | { \ |
137 | BAT *b, *s = NULL, *bn; \ |
138 | BUN i, cnt; \ |
139 | struct canditer ci; \ |
140 | oid x; \ |
141 | BUN nils = 0; \ |
142 | int e = 0, ex = 0; \ |
143 | \ |
144 | if ((b = BATdescriptor(*bid)) == NULL) { \ |
145 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
146 | } \ |
147 | if (sid != NULL && !is_bat_nil(*sid) && \ |
148 | (s = BATdescriptor(*sid)) == NULL) { \ |
149 | BBPunfix(b->batCacheid); \ |
150 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
151 | } \ |
152 | canditer_init(&ci, b, s); \ |
153 | cnt = BATcount(b); \ |
154 | bn = COLnew(b->hseqbase, TYPE_##TYPE, cnt, TRANSIENT); \ |
155 | if (bn == NULL) { \ |
156 | BBPunfix(b->batCacheid); \ |
157 | BBPunfix(s->batCacheid); \ |
158 | throw(MAL, "batcalc." #FUNC, SQLSTATE(HY001) MAL_MALLOC_FAIL); \ |
159 | } \ |
160 | \ |
161 | const TYPE *restrict src = (const TYPE *) Tloc(b, 0); \ |
162 | TYPE *restrict dst = (TYPE *) Tloc(bn, 0); \ |
163 | errno = 0; \ |
164 | feclearexcept(FE_ALL_EXCEPT); \ |
165 | for (i = 0; i < cnt; i++) { \ |
166 | x = canditer_next(&ci); \ |
167 | if (is_oid_nil(x)) \ |
168 | break; \ |
169 | x -= b->hseqbase; \ |
170 | while (i < x) { \ |
171 | dst[i++] = TYPE##_nil; \ |
172 | nils++; \ |
173 | } \ |
174 | if (is_##TYPE##_nil(src[i])) { \ |
175 | nils++; \ |
176 | dst[i] = TYPE##_nil; \ |
177 | } else { \ |
178 | dst[i] = FUNC##SUFF(src[i], *d); \ |
179 | } \ |
180 | } \ |
181 | while (i < cnt) { \ |
182 | dst[i++] = TYPE##_nil; \ |
183 | nils++; \ |
184 | } \ |
185 | e = errno; \ |
186 | ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); \ |
187 | BBPunfix(b->batCacheid); \ |
188 | if (s) \ |
189 | BBPunfix(s->batCacheid); \ |
190 | if (e != 0 || ex != 0) { \ |
191 | const char *err; \ |
192 | BBPunfix(bn->batCacheid); \ |
193 | if (e) \ |
194 | err = strerror(e); \ |
195 | else if (ex & FE_DIVBYZERO) \ |
196 | err = "Divide by zero"; \ |
197 | else if (ex & FE_OVERFLOW) \ |
198 | err = "Overflow"; \ |
199 | else \ |
200 | err = "Invalid result"; \ |
201 | throw(MAL, "batmmath." #FUNC, "Math exception: %s", err); \ |
202 | } \ |
203 | BATsetcount(bn, cnt); \ |
204 | bn->theap.dirty = true; \ |
205 | \ |
206 | bn->tsorted = false; \ |
207 | bn->trevsorted = false; \ |
208 | bn->tnil = nils != 0; \ |
209 | bn->tnonil = nils == 0; \ |
210 | BATkey(bn, false); \ |
211 | BBPkeepref(*ret = bn->batCacheid); \ |
212 | return MAL_SUCCEED; \ |
213 | } \ |
214 | \ |
215 | str CMDscience_bat_cst_##FUNC##_##TYPE(bat *ret, const bat *bid, \ |
216 | const TYPE *d) \ |
217 | { \ |
218 | return CMDscience_bat_cst_##FUNC##_##TYPE##_cand(ret, bid, d, NULL); \ |
219 | } \ |
220 | \ |
221 | str CMDscience_cst_bat_##FUNC##_##TYPE##_cand(bat *ret, const TYPE *d, \ |
222 | const bat *bid, const bat *sid) \ |
223 | { \ |
224 | BAT *b, *s = NULL, *bn; \ |
225 | BUN i, cnt; \ |
226 | struct canditer ci; \ |
227 | oid x; \ |
228 | BUN nils = 0; \ |
229 | int e = 0, ex = 0; \ |
230 | \ |
231 | if ((b = BATdescriptor(*bid)) == NULL) { \ |
232 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
233 | } \ |
234 | if (sid != NULL && !is_bat_nil(*sid) && \ |
235 | (s = BATdescriptor(*sid)) == NULL) { \ |
236 | BBPunfix(b->batCacheid); \ |
237 | throw(MAL, #TYPE, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \ |
238 | } \ |
239 | canditer_init(&ci, b, s); \ |
240 | cnt = BATcount(b); \ |
241 | bn = COLnew(b->hseqbase, TYPE_##TYPE, cnt, TRANSIENT); \ |
242 | if (bn == NULL) { \ |
243 | BBPunfix(b->batCacheid); \ |
244 | BBPunfix(s->batCacheid); \ |
245 | throw(MAL, "batcalc." #FUNC, SQLSTATE(HY001) MAL_MALLOC_FAIL); \ |
246 | } \ |
247 | \ |
248 | const TYPE *restrict src = (const TYPE *) Tloc(b, 0); \ |
249 | TYPE *restrict dst = (TYPE *) Tloc(bn, 0); \ |
250 | errno = 0; \ |
251 | feclearexcept(FE_ALL_EXCEPT); \ |
252 | for (i = 0; i < cnt; i++) { \ |
253 | x = canditer_next(&ci); \ |
254 | if (is_oid_nil(x)) \ |
255 | break; \ |
256 | x -= b->hseqbase; \ |
257 | while (i < x) { \ |
258 | dst[i++] = TYPE##_nil; \ |
259 | nils++; \ |
260 | } \ |
261 | if (is_##TYPE##_nil(src[i])) { \ |
262 | nils++; \ |
263 | dst[i] = TYPE##_nil; \ |
264 | } else { \ |
265 | dst[i] = FUNC##SUFF(*d, src[i]); \ |
266 | } \ |
267 | } \ |
268 | while (i < cnt) { \ |
269 | dst[i++] = TYPE##_nil; \ |
270 | nils++; \ |
271 | } \ |
272 | e = errno; \ |
273 | ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); \ |
274 | BBPunfix(b->batCacheid); \ |
275 | if (s) \ |
276 | BBPunfix(s->batCacheid); \ |
277 | if (e != 0 || ex != 0) { \ |
278 | const char *err; \ |
279 | BBPunfix(bn->batCacheid); \ |
280 | if (e) \ |
281 | err = strerror(e); \ |
282 | else if (ex & FE_DIVBYZERO) \ |
283 | err = "Divide by zero"; \ |
284 | else if (ex & FE_OVERFLOW) \ |
285 | err = "Overflow"; \ |
286 | else \ |
287 | err = "Invalid result"; \ |
288 | throw(MAL, "batmmath." #FUNC, "Math exception: %s", err); \ |
289 | } \ |
290 | BATsetcount(bn, cnt); \ |
291 | bn->theap.dirty = true; \ |
292 | \ |
293 | bn->tsorted = false; \ |
294 | bn->trevsorted = false; \ |
295 | bn->tnil = nils != 0; \ |
296 | bn->tnonil = nils == 0; \ |
297 | BATkey(bn, false); \ |
298 | BBPkeepref(*ret = bn->batCacheid); \ |
299 | return MAL_SUCCEED; \ |
300 | } \ |
301 | \ |
302 | str CMDscience_cst_bat_##FUNC##_##TYPE(bat *ret, const TYPE *d, \ |
303 | const bat *bid) \ |
304 | { \ |
305 | return CMDscience_cst_bat_##FUNC##_##TYPE##_cand(ret, d, bid, NULL); \ |
306 | } |
307 | |
308 | #define scienceImpl(Operator) \ |
309 | scienceFcnImpl(Operator,dbl,) \ |
310 | scienceFcnImpl(Operator,flt,f) |
311 | |
312 | #define scienceNotImpl(FUNC) \ |
313 | str CMDscience_bat_flt_##FUNC(bat *ret, const bat *bid) \ |
314 | { \ |
315 | (void)ret; \ |
316 | (void)bid; \ |
317 | throw(MAL, "batmmath." #FUNC, SQLSTATE(0A000) PROGRAM_NYI); \ |
318 | } \ |
319 | str CMDscience_bat_dbl_##FUNC(bat *ret, const bat *bid) \ |
320 | { \ |
321 | (void)ret; \ |
322 | (void)bid; \ |
323 | throw(MAL, "batmmath." #FUNC, SQLSTATE(0A000) PROGRAM_NYI); \ |
324 | } |
325 | |
326 | scienceImpl(asin) |
327 | scienceImpl(acos) |
328 | scienceImpl(atan) |
329 | scienceImpl(cos) |
330 | scienceImpl(sin) |
331 | scienceImpl(tan) |
332 | scienceImpl(cosh) |
333 | scienceImpl(sinh) |
334 | scienceImpl(tanh) |
335 | scienceImpl(radians) |
336 | scienceImpl(degrees) |
337 | scienceImpl(exp) |
338 | scienceImpl(log) |
339 | scienceImpl(log10) |
340 | scienceImpl(log2) |
341 | scienceImpl(sqrt) |
342 | #ifdef HAVE_CBRT |
343 | scienceImpl(cbrt) |
344 | #else |
345 | scienceNotImpl(cbrt) |
346 | #endif |
347 | scienceImpl(ceil) |
348 | scienceImpl(fabs) |
349 | scienceImpl(floor) |
350 | /* |
351 | * round is not binary... |
352 | * scienceBinaryImpl(round,int) |
353 | */ |
354 | scienceBinaryImpl(atan2,dbl,) |
355 | scienceBinaryImpl(atan2,flt,f) |
356 | scienceBinaryImpl(pow,dbl,) |
357 | scienceBinaryImpl(pow,flt,f) |
358 | scienceBinaryImpl(log,dbl,bs) |
359 | scienceBinaryImpl(log,flt,bsf) |
360 | |