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) \
48str 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 \
128str 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) \
134str 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 \
215str 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 \
221str 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 \
302str 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) \
313str 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} \
319str 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
326scienceImpl(asin)
327scienceImpl(acos)
328scienceImpl(atan)
329scienceImpl(cos)
330scienceImpl(sin)
331scienceImpl(tan)
332scienceImpl(cosh)
333scienceImpl(sinh)
334scienceImpl(tanh)
335scienceImpl(radians)
336scienceImpl(degrees)
337scienceImpl(exp)
338scienceImpl(log)
339scienceImpl(log10)
340scienceImpl(log2)
341scienceImpl(sqrt)
342#ifdef HAVE_CBRT
343scienceImpl(cbrt)
344#else
345scienceNotImpl(cbrt)
346#endif
347scienceImpl(ceil)
348scienceImpl(fabs)
349scienceImpl(floor)
350/*
351 * round is not binary...
352 * scienceBinaryImpl(round,int)
353 */
354scienceBinaryImpl(atan2,dbl,)
355scienceBinaryImpl(atan2,flt,f)
356scienceBinaryImpl(pow,dbl,)
357scienceBinaryImpl(pow,flt,f)
358scienceBinaryImpl(log,dbl,bs)
359scienceBinaryImpl(log,flt,bsf)
360