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