1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
50 #include "jsbuiltins.h"
52 #include "jsversion.h"
56 #include "jslibmath.h"
61 #define M_E 2.7182818284590452354
64 #define M_LOG2E 1.4426950408889634074
67 #define M_LOG10E 0.43429448190325182765
70 #define M_LN2 0.69314718055994530942
73 #define M_LN10 2.30258509299404568402
76 #define M_PI 3.14159265358979323846
79 #define M_SQRT2 1.41421356237309504880
82 #define M_SQRT1_2 0.70710678118654752440
85 static JSConstDoubleSpec math_constants
[] = {
86 {M_E
, "E", 0, {0,0,0}},
87 {M_LOG2E
, "LOG2E", 0, {0,0,0}},
88 {M_LOG10E
, "LOG10E", 0, {0,0,0}},
89 {M_LN2
, "LN2", 0, {0,0,0}},
90 {M_LN10
, "LN10", 0, {0,0,0}},
91 {M_PI
, "PI", 0, {0,0,0}},
92 {M_SQRT2
, "SQRT2", 0, {0,0,0}},
93 {M_SQRT1_2
, "SQRT1_2", 0, {0,0,0}},
97 Class js_MathClass
= {
99 JSCLASS_HAS_CACHED_PROTO(JSProto_Math
),
100 PropertyStub
, /* addProperty */
101 PropertyStub
, /* delProperty */
102 PropertyStub
, /* getProperty */
103 PropertyStub
, /* setProperty */
110 math_abs(JSContext
*cx
, uintN argc
, Value
*vp
)
115 vp
->setDouble(js_NaN
);
118 if (!ValueToNumber(cx
, vp
[2], &x
))
126 math_acos(JSContext
*cx
, uintN argc
, Value
*vp
)
131 vp
->setDouble(js_NaN
);
134 if (!ValueToNumber(cx
, vp
[2], &x
))
136 #if defined(SOLARIS) && defined(__GNUC__)
137 if (x
< -1 || 1 < x
) {
138 vp
->setDouble(js_NaN
);
148 math_asin(JSContext
*cx
, uintN argc
, Value
*vp
)
153 vp
->setDouble(js_NaN
);
156 if (!ValueToNumber(cx
, vp
[2], &x
))
158 #if defined(SOLARIS) && defined(__GNUC__)
159 if (x
< -1 || 1 < x
) {
160 vp
->setDouble(js_NaN
);
170 math_atan(JSContext
*cx
, uintN argc
, Value
*vp
)
175 vp
->setDouble(js_NaN
);
178 if (!ValueToNumber(cx
, vp
[2], &x
))
185 static inline jsdouble JS_FASTCALL
186 math_atan2_kernel(jsdouble x
, jsdouble y
)
188 #if defined(_MSC_VER)
190 * MSVC's atan2 does not yield the result demanded by ECMA when both x
191 * and y are infinite.
192 * - The result is a multiple of pi/4.
193 * - The sign of x determines the sign of the result.
194 * - The sign of y determines the multiplicator, 1 or 3.
196 if (JSDOUBLE_IS_INFINITE(x
) && JSDOUBLE_IS_INFINITE(y
)) {
197 jsdouble z
= js_copysign(M_PI
/ 4, x
);
204 #if defined(SOLARIS) && defined(__GNUC__)
206 if (JSDOUBLE_IS_NEGZERO(y
))
207 return js_copysign(M_PI
, x
);
216 math_atan2(JSContext
*cx
, uintN argc
, Value
*vp
)
221 vp
->setDouble(js_NaN
);
224 if (!ValueToNumber(cx
, vp
[2], &x
))
226 if (!ValueToNumber(cx
, vp
[3], &y
))
228 z
= math_atan2_kernel(x
, y
);
233 static inline jsdouble JS_FASTCALL
234 math_ceil_kernel(jsdouble x
)
237 if (x
< 0 && x
> -1.0)
238 return js_copysign(0, -1);
244 js_math_ceil(JSContext
*cx
, uintN argc
, Value
*vp
)
249 vp
->setDouble(js_NaN
);
252 if (!ValueToNumber(cx
, vp
[2], &x
))
254 z
= math_ceil_kernel(x
);
260 math_cos(JSContext
*cx
, uintN argc
, Value
*vp
)
265 vp
->setDouble(js_NaN
);
268 if (!ValueToNumber(cx
, vp
[2], &x
))
276 math_exp(JSContext
*cx
, uintN argc
, Value
*vp
)
281 vp
->setDouble(js_NaN
);
284 if (!ValueToNumber(cx
, vp
[2], &x
))
287 if (!JSDOUBLE_IS_NaN(x
)) {
288 if (x
== js_PositiveInfinity
) {
289 vp
->setDouble(js_PositiveInfinity
);
292 if (x
== js_NegativeInfinity
) {
304 js_math_floor(JSContext
*cx
, uintN argc
, Value
*vp
)
309 vp
->setDouble(js_NaN
);
312 if (!ValueToNumber(cx
, vp
[2], &x
))
320 math_log(JSContext
*cx
, uintN argc
, Value
*vp
)
325 vp
->setDouble(js_NaN
);
328 if (!ValueToNumber(cx
, vp
[2], &x
))
330 #if defined(SOLARIS) && defined(__GNUC__)
332 vp
->setDouble(js_NaN
);
342 js_math_max(JSContext
*cx
, uintN argc
, Value
*vp
)
344 jsdouble x
, z
= js_NegativeInfinity
;
349 vp
->setDouble(js_NegativeInfinity
);
353 for (i
= 0; i
< argc
; i
++) {
354 if (!ValueToNumber(cx
, argv
[i
], &x
))
356 if (JSDOUBLE_IS_NaN(x
)) {
357 vp
->setDouble(js_NaN
);
360 if (x
== 0 && x
== z
) {
361 if (js_copysign(1.0, z
) == -1)
372 js_math_min(JSContext
*cx
, uintN argc
, Value
*vp
)
374 jsdouble x
, z
= js_PositiveInfinity
;
379 vp
->setDouble(js_PositiveInfinity
);
383 for (i
= 0; i
< argc
; i
++) {
384 if (!ValueToNumber(cx
, argv
[i
], &x
))
386 if (JSDOUBLE_IS_NaN(x
)) {
387 vp
->setDouble(js_NaN
);
390 if (x
== 0 && x
== z
) {
391 if (js_copysign(1.0, x
) == -1)
402 powi(jsdouble x
, jsint y
)
404 jsuint n
= (y
< 0) ? -y
: y
;
408 if ((n
& 1) != 0) p
*= m
;
412 // Unfortunately, we have to be careful when p has reached
413 // infinity in the computation, because sometimes the higher
414 // internal precision in the pow() implementation would have
415 // given us a finite p. This happens very rarely.
417 jsdouble result
= 1.0 / p
;
418 return (result
== 0 && JSDOUBLE_IS_INFINITE(p
))
419 ? pow(x
, static_cast<jsdouble
>(y
)) // Avoid pow(double, int).
430 math_pow(JSContext
*cx
, uintN argc
, Value
*vp
)
435 vp
->setDouble(js_NaN
);
438 if (!ValueToNumber(cx
, vp
[2], &x
))
440 if (!ValueToNumber(cx
, vp
[3], &y
))
443 * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
444 * when x = -0.0, so we have to guard for this.
446 if (JSDOUBLE_IS_FINITE(x
) && x
!= 0.0) {
448 vp
->setNumber(sqrt(x
));
452 vp
->setNumber(1.0/sqrt(x
));
457 * Because C99 and ECMA specify different behavior for pow(),
458 * we need to wrap the libm call to make it ECMA compliant.
460 if (!JSDOUBLE_IS_FINITE(y
) && (x
== 1.0 || x
== -1.0)) {
461 vp
->setDouble(js_NaN
);
464 /* pow(x, +-0) is always 1, even for x = NaN. */
471 z
= powi(x
, vp
[3].toInt32());
479 static const int64 RNG_MULTIPLIER
= 0x5DEECE66DLL
;
480 static const int64 RNG_ADDEND
= 0xBLL
;
481 static const int64 RNG_MASK
= (1LL << 48) - 1;
482 static const jsdouble RNG_DSCALE
= jsdouble(1LL << 53);
485 * Math.random() support, lifted from java.util.Random.java.
488 random_setSeed(JSContext
*cx
, int64 seed
)
490 cx
->rngSeed
= (seed
^ RNG_MULTIPLIER
) & RNG_MASK
;
494 js_InitRandom(JSContext
*cx
)
497 * Set the seed from current time. Since we have a RNG per context and we often bring
498 * up several contexts at the same time, we xor in some additional values, namely
499 * the context and its successor. We don't just use the context because it might be
500 * possible to reverse engineer the context pointer if one guesses the time right.
503 (PRMJ_Now() / 1000) ^
505 int64(cx
->link
.next
));
509 random_next(JSContext
*cx
, int bits
)
511 uint64 nextseed
= cx
->rngSeed
* RNG_MULTIPLIER
;
512 nextseed
+= RNG_ADDEND
;
513 nextseed
&= RNG_MASK
;
514 cx
->rngSeed
= nextseed
;
515 return nextseed
>> (48 - bits
);
518 static inline jsdouble
519 random_nextDouble(JSContext
*cx
)
521 return jsdouble((random_next(cx
, 26) << 27) + random_next(cx
, 27)) / RNG_DSCALE
;
525 math_random(JSContext
*cx
, uintN argc
, Value
*vp
)
527 jsdouble z
= random_nextDouble(cx
);
532 #if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
533 /* Try to work around apparent _copysign bustage in VC7.x. */
535 js_copysign(double x
, double y
)
541 xu
.s
.hi
&= ~JSDOUBLE_HI32_SIGNBIT
;
542 xu
.s
.hi
|= yu
.s
.hi
& JSDOUBLE_HI32_SIGNBIT
;
548 js_math_round(JSContext
*cx
, uintN argc
, Value
*vp
)
553 vp
->setDouble(js_NaN
);
556 if (!ValueToNumber(cx
, vp
[2], &x
))
558 z
= js_copysign(floor(x
+ 0.5), x
);
564 math_sin(JSContext
*cx
, uintN argc
, Value
*vp
)
569 vp
->setDouble(js_NaN
);
572 if (!ValueToNumber(cx
, vp
[2], &x
))
580 math_sqrt(JSContext
*cx
, uintN argc
, Value
*vp
)
585 vp
->setDouble(js_NaN
);
588 if (!ValueToNumber(cx
, vp
[2], &x
))
596 math_tan(JSContext
*cx
, uintN argc
, Value
*vp
)
601 vp
->setDouble(js_NaN
);
604 if (!ValueToNumber(cx
, vp
[2], &x
))
613 math_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
615 vp
->setString(ATOM_TO_STRING(CLASS_ATOM(cx
, Math
)));
622 #define MATH_BUILTIN_1(name) MATH_BUILTIN_CFUN_1(name, name)
623 #define MATH_BUILTIN_CFUN_1(name, cfun) \
624 static jsdouble FASTCALL math_##name##_tn(jsdouble d) { return cfun(d); } \
625 JS_DEFINE_TRCINFO_1(math_##name, \
626 (1, (static, DOUBLE, math_##name##_tn, DOUBLE, 1, nanojit::ACCSET_NONE)))
628 MATH_BUILTIN_CFUN_1(abs
, fabs
)
635 static jsdouble FASTCALL
636 math_acos_tn(jsdouble d
)
638 #if defined(SOLARIS) && defined(__GNUC__)
639 if (d
< -1 || 1 < d
) {
646 static jsdouble FASTCALL
647 math_asin_tn(jsdouble d
)
649 #if defined(SOLARIS) && defined(__GNUC__)
650 if (d
< -1 || 1 < d
) {
659 static jsdouble FASTCALL
660 math_exp_tn(JSContext
*cx
, jsdouble d
)
662 if (!JSDOUBLE_IS_NaN(d
)) {
663 if (d
== js_PositiveInfinity
)
664 return js_PositiveInfinity
;
665 if (d
== js_NegativeInfinity
)
671 JS_DEFINE_TRCINFO_1(math_exp
,
672 (2, (static, DOUBLE
, math_exp_tn
, CONTEXT
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
680 static jsdouble FASTCALL
681 math_log_tn(jsdouble d
)
683 #if defined(SOLARIS) && defined(__GNUC__)
690 static jsdouble FASTCALL
691 math_max_tn(jsdouble d
, jsdouble p
)
693 if (JSDOUBLE_IS_NaN(d
) || JSDOUBLE_IS_NaN(p
))
696 if (p
== 0 && p
== d
) {
697 // Max prefers 0.0 to -0.0.
698 if (js_copysign(1.0, d
) == -1)
702 return (p
> d
) ? p
: d
;
705 static jsdouble FASTCALL
706 math_min_tn(jsdouble d
, jsdouble p
)
708 if (JSDOUBLE_IS_NaN(d
) || JSDOUBLE_IS_NaN(p
))
711 if (p
== 0 && p
== d
) {
712 // Min prefers -0.0 to 0.0.
713 if (js_copysign (1.0, p
) == -1)
717 return (p
< d
) ? p
: d
;
720 static jsdouble FASTCALL
721 math_pow_tn(jsdouble d
, jsdouble p
)
724 * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
725 * when x = -0.0, so we have to guard for this.
727 if (JSDOUBLE_IS_FINITE(d
) && d
!= 0.0) {
734 if (!JSDOUBLE_IS_FINITE(p
) && (d
== 1.0 || d
== -1.0))
739 if (JSDOUBLE_IS_INT32(p
, &i
))
745 static jsdouble FASTCALL
746 math_random_tn(JSContext
*cx
)
748 return random_nextDouble(cx
);
751 static jsdouble FASTCALL
752 math_round_tn(jsdouble x
)
754 return js_copysign(floor(x
+ 0.5), x
);
757 static jsdouble FASTCALL
758 math_ceil_tn(jsdouble x
)
760 return math_ceil_kernel(x
);
763 static jsdouble FASTCALL
764 math_floor_tn(jsdouble x
)
769 JS_DEFINE_TRCINFO_1(math_acos
,
770 (1, (static, DOUBLE
, math_acos_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
771 JS_DEFINE_TRCINFO_1(math_asin
,
772 (1, (static, DOUBLE
, math_asin_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
773 JS_DEFINE_TRCINFO_1(math_atan2
,
774 (2, (static, DOUBLE
, math_atan2_kernel
, DOUBLE
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
775 JS_DEFINE_TRCINFO_1(js_math_floor
,
776 (1, (static, DOUBLE
, math_floor_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
777 JS_DEFINE_TRCINFO_1(math_log
,
778 (1, (static, DOUBLE
, math_log_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
779 JS_DEFINE_TRCINFO_1(js_math_max
,
780 (2, (static, DOUBLE
, math_max_tn
, DOUBLE
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
781 JS_DEFINE_TRCINFO_1(js_math_min
,
782 (2, (static, DOUBLE
, math_min_tn
, DOUBLE
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
783 JS_DEFINE_TRCINFO_1(math_pow
,
784 (2, (static, DOUBLE
, math_pow_tn
, DOUBLE
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
785 JS_DEFINE_TRCINFO_1(math_random
,
786 (1, (static, DOUBLE
, math_random_tn
, CONTEXT
, 0, nanojit::ACCSET_STORE_ANY
)))
787 JS_DEFINE_TRCINFO_1(js_math_round
,
788 (1, (static, DOUBLE
, math_round_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
789 JS_DEFINE_TRCINFO_1(js_math_ceil
,
790 (1, (static, DOUBLE
, math_ceil_tn
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
792 #endif /* JS_TRACER */
794 static JSFunctionSpec math_static_methods
[] = {
796 JS_FN(js_toSource_str
, math_toSource
, 0, 0),
798 JS_TN("abs", math_abs
, 1, 0, &math_abs_trcinfo
),
799 JS_TN("acos", math_acos
, 1, 0, &math_acos_trcinfo
),
800 JS_TN("asin", math_asin
, 1, 0, &math_asin_trcinfo
),
801 JS_TN("atan", math_atan
, 1, 0, &math_atan_trcinfo
),
802 JS_TN("atan2", math_atan2
, 2, 0, &math_atan2_trcinfo
),
803 JS_TN("ceil", js_math_ceil
, 1, 0, &js_math_ceil_trcinfo
),
804 JS_TN("cos", math_cos
, 1, 0, &math_cos_trcinfo
),
805 JS_TN("exp", math_exp
, 1, 0, &math_exp_trcinfo
),
806 JS_TN("floor", js_math_floor
, 1, 0, &js_math_floor_trcinfo
),
807 JS_TN("log", math_log
, 1, 0, &math_log_trcinfo
),
808 JS_TN("max", js_math_max
, 2, 0, &js_math_max_trcinfo
),
809 JS_TN("min", js_math_min
, 2, 0, &js_math_min_trcinfo
),
810 JS_TN("pow", math_pow
, 2, 0, &math_pow_trcinfo
),
811 JS_TN("random", math_random
, 0, 0, &math_random_trcinfo
),
812 JS_TN("round", js_math_round
, 1, 0, &js_math_round_trcinfo
),
813 JS_TN("sin", math_sin
, 1, 0, &math_sin_trcinfo
),
814 JS_TN("sqrt", math_sqrt
, 1, 0, &math_sqrt_trcinfo
),
815 JS_TN("tan", math_tan
, 1, 0, &math_tan_trcinfo
),
820 js_InitMathClass(JSContext
*cx
, JSObject
*obj
)
824 Math
= JS_NewObject(cx
, Jsvalify(&js_MathClass
), NULL
, obj
);
827 if (!JS_DefineProperty(cx
, obj
, js_Math_str
, OBJECT_TO_JSVAL(Math
),
828 JS_PropertyStub
, JS_PropertyStub
, 0)) {
832 if (!JS_DefineFunctions(cx
, Math
, math_static_methods
))
834 if (!JS_DefineConstDoubles(cx
, Math
, math_constants
))