1 /*
2  * Copyright (c) 2003
3  *      David Leonard.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of David Leonard nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #if STDC_HEADERS
36 # include <stdlib.h>
37 #endif
38 
39 #include <see/mem.h>
40 #include <see/value.h>
41 #include <see/string.h>
42 #include <see/object.h>
43 #include <see/native.h>
44 #include <see/cfunction.h>
45 #include <see/error.h>
46 #include <see/interpreter.h>
47 
48 #include "stringdefs.h"
49 #include "init.h"
50 #include "nmath.h"
51 
52 /*
53  * 15.8 The Math object.
54  */
55 
56 #define SET_NO_RESULT(res)	SEE_SET_NUMBER(res, SEE_NaN)
57 #define IS_NEGZERO(n)		((n) == 0 && SEE_COPYSIGN(1.0, n) < 0)
58 #define IS_POSZERO(n)		((n) == 0 && SEE_COPYSIGN(1.0, n) > 0)
59 
60 static void math_abs(struct SEE_interpreter *, struct SEE_object *,
61         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
62 static void math_acos(struct SEE_interpreter *, struct SEE_object *,
63         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
64 static void math_asin(struct SEE_interpreter *, struct SEE_object *,
65         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
66 static void math_atan(struct SEE_interpreter *, struct SEE_object *,
67         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
68 static void math_atan2(struct SEE_interpreter *, struct SEE_object *,
69         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
70 static void math_ceil(struct SEE_interpreter *, struct SEE_object *,
71         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
72 static void math_cos(struct SEE_interpreter *, struct SEE_object *,
73         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
74 static void math_exp(struct SEE_interpreter *, struct SEE_object *,
75         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
76 static void math_floor(struct SEE_interpreter *, struct SEE_object *,
77         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
78 static void math_log(struct SEE_interpreter *, struct SEE_object *,
79         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
80 static void math_max(struct SEE_interpreter *, struct SEE_object *,
81         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
82 static void math_min(struct SEE_interpreter *, struct SEE_object *,
83         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
84 static void math_pow(struct SEE_interpreter *, struct SEE_object *,
85         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
86 static void math_random(struct SEE_interpreter *, struct SEE_object *,
87         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
88 static void math_round(struct SEE_interpreter *, struct SEE_object *,
89         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
90 static void math_sin(struct SEE_interpreter *, struct SEE_object *,
91         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
92 static void math_sqrt(struct SEE_interpreter *, struct SEE_object *,
93         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
94 static void math_tan(struct SEE_interpreter *, struct SEE_object *,
95         struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
96 
97 /* Math is a normal native object */
98 static struct SEE_objectclass math_class = {
99 	"Math",				/* Class */
100 	SEE_native_get,			/* Get */
101 	SEE_native_put,			/* Put */
102 	SEE_native_canput,		/* CanPut */
103 	SEE_native_hasproperty,		/* HasProperty */
104 	SEE_native_delete,		/* Delete */
105 	SEE_native_defaultvalue,	/* DefaultValue */
106 	SEE_native_enumerator,		/* DefaultValue */
107 	NULL,				/* Construct */
108 	NULL				/* Call */
109 };
110 
111 void
SEE_Math_alloc(interp)112 SEE_Math_alloc(interp)
113 	struct SEE_interpreter *interp;
114 {
115 	interp->Math =
116 	    (struct SEE_object *)SEE_NEW(interp, struct SEE_native);
117 }
118 
119 void
SEE_Math_init(interp)120 SEE_Math_init(interp)
121 	struct SEE_interpreter *interp;
122 {
123 	struct SEE_object *Math;		/* struct SEE_native */
124 	struct SEE_value v;
125 
126 	Math = interp->Math;
127 	SEE_native_init((struct SEE_native *)Math, interp,
128 		&math_class, interp->Object_prototype);
129 
130 #define PUTVAL(name, val) 						\
131 	SEE_SET_NUMBER(&v, val); 					\
132 	SEE_OBJECT_PUT(interp, Math, STR(name), &v,			\
133 		SEE_ATTR_DONTENUM | SEE_ATTR_DONTDELETE | 		\
134 		SEE_ATTR_READONLY);
135 
136 	PUTVAL(E, M_E)				/* 15.8.1.1 */
137 	PUTVAL(LN10, M_LN10)			/* 15.8.1.2 */
138 	PUTVAL(LN2, M_LN2)			/* 15.8.1.3 */
139 	PUTVAL(LOG2E, M_LOG2E)			/* 15.8.1.4 */
140 	PUTVAL(LOG10E, M_LOG10E)		/* 15.8.1.5 */
141 	PUTVAL(PI, M_PI)			/* 15.8.1.6 */
142 	PUTVAL(SQRT1_2, M_SQRT1_2)		/* 15.8.1.7 */
143 	PUTVAL(SQRT2, M_SQRT2)			/* 15.8.1.8 */
144 
145 #define PUTFUNC(name, len) 						\
146 	SEE_SET_OBJECT(&v, SEE_cfunction_make(interp, math_##name, 	\
147 		STR(name), len));					\
148 	SEE_OBJECT_PUT(interp, Math, STR(name), &v, 			\
149 		SEE_ATTR_DEFAULT);
150 
151 	PUTFUNC(abs, 1)				/* 15.8.2.1 */
152 	PUTFUNC(acos, 1)			/* 15.8.2.2 */
153 	PUTFUNC(asin, 1)			/* 15.8.2.3 */
154 	PUTFUNC(atan, 1)			/* 15.8.2.4 */
155 	PUTFUNC(atan2, 2)			/* 15.8.2.5 */
156 	PUTFUNC(ceil, 1)			/* 15.8.2.6 */
157 	PUTFUNC(cos, 1)				/* 15.8.2.7 */
158 	PUTFUNC(exp, 1)				/* 15.8.2.8 */
159 	PUTFUNC(floor, 1)			/* 15.8.2.9 */
160 	PUTFUNC(log, 1)				/* 15.8.2.10 */
161 	PUTFUNC(max, 2)				/* 15.8.2.11 */
162 	PUTFUNC(min, 2)				/* 15.8.2.12 */
163 	PUTFUNC(pow, 2)				/* 15.8.2.13 */
164 	PUTFUNC(random, 0)			/* 15.8.2.14 */
165 	PUTFUNC(round, 1)			/* 15.8.2.15 */
166 	PUTFUNC(sin, 1)				/* 15.8.2.16 */
167 	PUTFUNC(sqrt, 1)			/* 15.8.2.17 */
168 	PUTFUNC(tan, 1)				/* 15.8.2.18 */
169 }
170 
171 /* 15.8.2.1 Math.abs() */
172 static void
math_abs(interp,self,thisobj,argc,argv,res)173 math_abs(interp, self, thisobj, argc, argv, res)
174 	struct SEE_interpreter *interp;
175 	struct SEE_object *self, *thisobj;
176 	int argc;
177 	struct SEE_value **argv, *res;
178 {
179 	if (argc == 0)
180 		SET_NO_RESULT(res);
181 	else {
182 		SEE_ToNumber(interp, argv[0], res);
183 		if (!SEE_NUMBER_ISNAN(res))
184 			res->u.number = SEE_COPYSIGN(res->u.number, 1.0);
185 	}
186 }
187 
188 /* 15.8.2.2 Math.acos() */
189 static void
math_acos(interp,self,thisobj,argc,argv,res)190 math_acos(interp, self, thisobj, argc, argv, res)
191 	struct SEE_interpreter *interp;
192 	struct SEE_object *self, *thisobj;
193 	int argc;
194 	struct SEE_value **argv, *res;
195 {
196 	if (argc == 0)
197 		SET_NO_RESULT(res);
198 	else {
199 		SEE_ToNumber(interp, argv[0], res);
200 		if (SEE_NUMBER_ISNAN(res))
201 			;
202 		else if (res->u.number < -1 || res->u.number > 1)
203 			SEE_SET_NUMBER(res, SEE_NaN);
204 		else if (res->u.number == 1)
205 			SEE_SET_NUMBER(res, 0);
206 		else
207 			SEE_SET_NUMBER(res, NUMBER_acos(res->u.number));
208 	}
209 }
210 
211 
212 /* 15.8.2.3 Math.asin() */
213 static void
math_asin(interp,self,thisobj,argc,argv,res)214 math_asin(interp, self, thisobj, argc, argv, res)
215 	struct SEE_interpreter *interp;
216 	struct SEE_object *self, *thisobj;
217 	int argc;
218 	struct SEE_value **argv, *res;
219 {
220 	if (argc == 0)
221 		SET_NO_RESULT(res);
222 	else {
223 		SEE_ToNumber(interp, argv[0], res);
224 		if (SEE_NUMBER_ISNAN(res))
225 			;
226 		else if (res->u.number < -1 || res->u.number > 1)
227 			SEE_SET_NUMBER(res, SEE_NaN);
228 		else if (res->u.number == 0)
229 			;
230 		else
231 			SEE_SET_NUMBER(res, NUMBER_asin(res->u.number));
232 	}
233 }
234 
235 /* 15.8.2.4 Math.atan() */
236 static void
math_atan(interp,self,thisobj,argc,argv,res)237 math_atan(interp, self, thisobj, argc, argv, res)
238 	struct SEE_interpreter *interp;
239 	struct SEE_object *self, *thisobj;
240 	int argc;
241 	struct SEE_value **argv, *res;
242 {
243 	struct SEE_value v;
244 
245 	if (argc == 0)
246 		SET_NO_RESULT(res);
247 	else {
248 		SEE_ToNumber(interp, argv[0], &v);
249 		if (v.u.number == 0)
250 			SEE_SET_NUMBER(res, v.u.number);
251 		else
252 			SEE_SET_NUMBER(res, NUMBER_atan(v.u.number));
253 	}
254 }
255 
256 /* 15.8.2.5 Math.atan2() */
257 static void
math_atan2(interp,self,thisobj,argc,argv,res)258 math_atan2(interp, self, thisobj, argc, argv, res)
259 	struct SEE_interpreter *interp;
260 	struct SEE_object *self, *thisobj;
261 	int argc;
262 	struct SEE_value **argv, *res;
263 {
264 	struct SEE_value v1, v2;
265 
266 	if (argc < 2)
267 		SET_NO_RESULT(res);
268 	else {
269 		SEE_number_t x, y;
270 		SEE_ToNumber(interp, argv[0], &v1);
271 		SEE_ToNumber(interp, argv[1], &v2);
272 
273 		y = v1.u.number;
274 		x = v2.u.number;
275 
276 		/*
277 		 * XXX: on my system, atan2() only differs in
278 		 * the case where x is -0
279 		 */
280 		if (IS_POSZERO(y) && IS_NEGZERO(x))
281 			SEE_SET_NUMBER(res, M_PI);
282 		else if (IS_NEGZERO(y) && IS_NEGZERO(x))
283 			SEE_SET_NUMBER(res, -M_PI);
284 		else
285 			SEE_SET_NUMBER(res, NUMBER_atan2(y, x));
286 	}
287 }
288 
289 /* 15.8.2.6 Math.ceil() */
290 static void
math_ceil(interp,self,thisobj,argc,argv,res)291 math_ceil(interp, self, thisobj, argc, argv, res)
292 	struct SEE_interpreter *interp;
293 	struct SEE_object *self, *thisobj;
294 	int argc;
295 	struct SEE_value **argv, *res;
296 {
297 	struct SEE_value v;
298 
299 	if (argc == 0)
300 		SET_NO_RESULT(res);
301 	else {
302 		SEE_ToNumber(interp, argv[0], &v);
303 		SEE_SET_NUMBER(res, NUMBER_ceil(v.u.number));
304 	}
305 }
306 
307 /* 15.8.2.7 Math.cos() */
308 static void
math_cos(interp,self,thisobj,argc,argv,res)309 math_cos(interp, self, thisobj, argc, argv, res)
310 	struct SEE_interpreter *interp;
311 	struct SEE_object *self, *thisobj;
312 	int argc;
313 	struct SEE_value **argv, *res;
314 {
315 	struct SEE_value v;
316 
317 	if (argc == 0)
318 		SET_NO_RESULT(res);
319 	else {
320 		SEE_ToNumber(interp, argv[0], &v);
321 		SEE_SET_NUMBER(res, NUMBER_cos(v.u.number));
322 	}
323 }
324 
325 /* 15.8.2.8 Math.exp() */
326 static void
math_exp(interp,self,thisobj,argc,argv,res)327 math_exp(interp, self, thisobj, argc, argv, res)
328 	struct SEE_interpreter *interp;
329 	struct SEE_object *self, *thisobj;
330 	int argc;
331 	struct SEE_value **argv, *res;
332 {
333 	struct SEE_value v;
334 
335 	if (argc == 0)
336 		SET_NO_RESULT(res);
337 	else {
338 		SEE_ToNumber(interp, argv[0], &v);
339 		if (!SEE_NUMBER_ISFINITE(&v) && !SEE_NUMBER_ISNAN(&v))
340 			SEE_SET_NUMBER(res, v.u.number < 0 ? 0 : SEE_Infinity);
341 		else
342 			SEE_SET_NUMBER(res, NUMBER_exp(v.u.number));
343 	}
344 }
345 
346 /* 15.8.2.9 Math.floor() */
347 static void
math_floor(interp,self,thisobj,argc,argv,res)348 math_floor(interp, self, thisobj, argc, argv, res)
349 	struct SEE_interpreter *interp;
350 	struct SEE_object *self, *thisobj;
351 	int argc;
352 	struct SEE_value **argv, *res;
353 {
354 	struct SEE_value v;
355 
356 	if (argc == 0)
357 		SET_NO_RESULT(res);
358 	else {
359 		SEE_ToNumber(interp, argv[0], &v);
360 		SEE_SET_NUMBER(res, NUMBER_floor(v.u.number));
361 	}
362 }
363 
364 /* 15.8.2.10 Math.log() */
365 static void
math_log(interp,self,thisobj,argc,argv,res)366 math_log(interp, self, thisobj, argc, argv, res)
367 	struct SEE_interpreter *interp;
368 	struct SEE_object *self, *thisobj;
369 	int argc;
370 	struct SEE_value **argv, *res;
371 {
372 	struct SEE_value v;
373 
374 	if (argc == 0)
375 		SET_NO_RESULT(res);
376 	else {
377 		SEE_ToNumber(interp, argv[0], &v);
378 		if (v.u.number < 0)
379 		    SEE_SET_NUMBER(res, SEE_NaN);
380 		else
381 		    SEE_SET_NUMBER(res, NUMBER_log(v.u.number));
382 	}
383 }
384 
385 /* 15.8.2.11 Math.max() */
386 static void
math_max(interp,self,thisobj,argc,argv,res)387 math_max(interp, self, thisobj, argc, argv, res)
388 	struct SEE_interpreter *interp;
389 	struct SEE_object *self, *thisobj;
390 	int argc;
391 	struct SEE_value **argv, *res;
392 {
393 	SEE_number_t maxnum = -SEE_Infinity;
394 	int i;
395 
396 	for (i = 0; i < argc; i++) {
397 	    SEE_ToNumber(interp, argv[i], res);
398 	    if (SEE_NUMBER_ISNAN(res))
399 		return;
400 	    if (i == 0 || res->u.number > maxnum ||
401 	        (res->u.number == 0 && IS_NEGZERO(maxnum)))
402 		maxnum = res->u.number;
403 	}
404 	SEE_SET_NUMBER(res, maxnum);
405 }
406 
407 /* 15.8.2.12 Math.min() */
408 static void
math_min(interp,self,thisobj,argc,argv,res)409 math_min(interp, self, thisobj, argc, argv, res)
410 	struct SEE_interpreter *interp;
411 	struct SEE_object *self, *thisobj;
412 	int argc;
413 	struct SEE_value **argv, *res;
414 {
415 	SEE_number_t minnum = SEE_Infinity;
416 	int i;
417 
418 	for (i = 0; i < argc; i++) {
419 	    SEE_ToNumber(interp, argv[i], res);
420 	    if (SEE_NUMBER_ISNAN(res))
421 		return;
422 	    if (i == 0 || res->u.number < minnum ||
423 	        (minnum == 0 && IS_NEGZERO(res->u.number)))
424 		minnum = res->u.number;
425 	}
426 	SEE_SET_NUMBER(res, minnum);
427 }
428 
429 /* 15.8.2.13 Math.pow() */
430 static void
math_pow(interp,self,thisobj,argc,argv,res)431 math_pow(interp, self, thisobj, argc, argv, res)
432 	struct SEE_interpreter *interp;
433 	struct SEE_object *self, *thisobj;
434 	int argc;
435 	struct SEE_value **argv, *res;
436 {
437 	struct SEE_value v1, v2;
438 
439 	if (argc < 2)
440 		SET_NO_RESULT(res);
441 	else {
442 		SEE_ToNumber(interp, argv[0], &v1);
443 		SEE_ToNumber(interp, argv[1], &v2);
444 
445 		if (IS_NEGZERO(v1.u.number) && v2.u.number < 0)
446 			SEE_SET_NUMBER(res, SEE_COPYSIGN(
447 			    NUMBER_fmod(v2.u.number, 2.0), 1.0) == 1
448 				? -SEE_Infinity : SEE_Infinity);
449 		else if (v1.u.number == 0 && v2.u.number < 0)
450 			SEE_SET_NUMBER(res,
451 				SEE_COPYSIGN(SEE_Infinity, v1.u.number));
452 		else
453 			SEE_SET_NUMBER(res,
454 				NUMBER_pow(v1.u.number, v2.u.number));
455 	}
456 }
457 
458 /* 15.8.2.14 Math.random() */
459 static void
math_random(interp,self,thisobj,argc,argv,res)460 math_random(interp, self, thisobj, argc, argv, res)
461 	struct SEE_interpreter *interp;
462 	struct SEE_object *self, *thisobj;
463 	int argc;
464 	struct SEE_value **argv, *res;
465 {
466 	unsigned int rval;
467 
468 #if HAVE_RAND_R
469 	rval = rand_r(&interp->random_seed);
470 #else
471 	/* XXX this is not thread safe */
472 	static int srand_initialised = 0;
473 	if (!srand_initialised) {
474 		srand_initialised++;
475 		srand(interp->random_seed);
476 	}
477 	rval = rand();
478 #endif
479 	SEE_SET_NUMBER(res, (SEE_number_t)rval / RAND_MAX);
480 }
481 
482 /* 15.8.2.15 Math.round() */
483 static void
math_round(interp,self,thisobj,argc,argv,res)484 math_round(interp, self, thisobj, argc, argv, res)
485 	struct SEE_interpreter *interp;
486 	struct SEE_object *self, *thisobj;
487 	int argc;
488 	struct SEE_value **argv, *res;
489 {
490 	struct SEE_value v;
491 	SEE_number_t x;
492 
493 	if (argc == 0)
494 		SET_NO_RESULT(res);
495 	else {
496 		SEE_ToNumber(interp, argv[0], &v);
497 		x = v.u.number;
498 		if (IS_NEGZERO(x) || (x >= -0.5 && x < 0))
499 		    SEE_SET_NUMBER(res, -0.0);
500 		else
501 		    SEE_SET_NUMBER(res, NUMBER_floor(v.u.number + 0.5));
502 	}
503 }
504 
505 /* 15.8.2.16 Math.sin() */
506 static void
math_sin(interp,self,thisobj,argc,argv,res)507 math_sin(interp, self, thisobj, argc, argv, res)
508 	struct SEE_interpreter *interp;
509 	struct SEE_object *self, *thisobj;
510 	int argc;
511 	struct SEE_value **argv, *res;
512 {
513 	struct SEE_value v;
514 
515 	if (argc == 0)
516 		SET_NO_RESULT(res);
517 	else {
518 		SEE_ToNumber(interp, argv[0], &v);
519 		SEE_SET_NUMBER(res, NUMBER_sin(v.u.number));
520 	}
521 }
522 
523 /* 15.8.2.17 Math.sqrt() */
524 static void
math_sqrt(interp,self,thisobj,argc,argv,res)525 math_sqrt(interp, self, thisobj, argc, argv, res)
526 	struct SEE_interpreter *interp;
527 	struct SEE_object *self, *thisobj;
528 	int argc;
529 	struct SEE_value **argv, *res;
530 {
531 	struct SEE_value v;
532 
533 	if (argc == 0)
534 		SET_NO_RESULT(res);
535 	else {
536 		SEE_ToNumber(interp, argv[0], &v);
537 		SEE_SET_NUMBER(res, NUMBER_sqrt(v.u.number));
538 	}
539 }
540 
541 /* 15.8.2.18 Math.tan() */
542 static void
math_tan(interp,self,thisobj,argc,argv,res)543 math_tan(interp, self, thisobj, argc, argv, res)
544 	struct SEE_interpreter *interp;
545 	struct SEE_object *self, *thisobj;
546 	int argc;
547 	struct SEE_value **argv, *res;
548 {
549 	struct SEE_value v;
550 
551 	if (argc == 0)
552 		SET_NO_RESULT(res);
553 	else {
554 		SEE_ToNumber(interp, argv[0], &v);
555 		SEE_SET_NUMBER(res, NUMBER_tan(v.u.number));
556 	}
557 }
558