| 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 |  |