2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2007, 2008, 2013 Apple Inc. All Rights Reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "MathObject.h"
25 #include "MathCommon.h"
26 #include "ObjectPrototype.h"
27 #include "JSCInlines.h"
29 #include <wtf/Assertions.h>
30 #include <wtf/MathExtras.h>
31 #include <wtf/RandomNumber.h>
32 #include <wtf/RandomNumberSeed.h>
33 #include <wtf/Vector.h>
37 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(MathObject
);
39 EncodedJSValue JSC_HOST_CALL
mathProtoFuncACos(ExecState
*);
40 EncodedJSValue JSC_HOST_CALL
mathProtoFuncACosh(ExecState
*);
41 EncodedJSValue JSC_HOST_CALL
mathProtoFuncASin(ExecState
*);
42 EncodedJSValue JSC_HOST_CALL
mathProtoFuncASinh(ExecState
*);
43 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATan(ExecState
*);
44 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATanh(ExecState
*);
45 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATan2(ExecState
*);
46 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCbrt(ExecState
*);
47 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCeil(ExecState
*);
48 EncodedJSValue JSC_HOST_CALL
mathProtoFuncClz32(ExecState
*);
49 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCos(ExecState
*);
50 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCosh(ExecState
*);
51 EncodedJSValue JSC_HOST_CALL
mathProtoFuncExp(ExecState
*);
52 EncodedJSValue JSC_HOST_CALL
mathProtoFuncExpm1(ExecState
*);
53 EncodedJSValue JSC_HOST_CALL
mathProtoFuncFround(ExecState
*);
54 EncodedJSValue JSC_HOST_CALL
mathProtoFuncHypot(ExecState
*);
55 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog(ExecState
*);
56 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog1p(ExecState
*);
57 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog10(ExecState
*);
58 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog2(ExecState
*);
59 EncodedJSValue JSC_HOST_CALL
mathProtoFuncMax(ExecState
*);
60 EncodedJSValue JSC_HOST_CALL
mathProtoFuncMin(ExecState
*);
61 EncodedJSValue JSC_HOST_CALL
mathProtoFuncPow(ExecState
*);
62 EncodedJSValue JSC_HOST_CALL
mathProtoFuncRandom(ExecState
*);
63 EncodedJSValue JSC_HOST_CALL
mathProtoFuncRound(ExecState
*);
64 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSign(ExecState
*);
65 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSin(ExecState
*);
66 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSinh(ExecState
*);
67 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSqrt(ExecState
*);
68 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTan(ExecState
*);
69 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTanh(ExecState
*);
70 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTrunc(ExecState
*);
71 EncodedJSValue JSC_HOST_CALL
mathProtoFuncIMul(ExecState
*);
77 const ClassInfo
MathObject::s_info
= { "Math", &Base::s_info
, 0, CREATE_METHOD_TABLE(MathObject
) };
79 MathObject::MathObject(VM
& vm
, Structure
* structure
)
80 : JSNonFinalObject(vm
, structure
)
84 void MathObject::finishCreation(VM
& vm
, JSGlobalObject
* globalObject
)
86 Base::finishCreation(vm
);
87 ASSERT(inherits(info()));
89 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "E"), jsNumber(exp(1.0)), DontDelete
| DontEnum
| ReadOnly
);
90 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "LN2"), jsNumber(log(2.0)), DontDelete
| DontEnum
| ReadOnly
);
91 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "LN10"), jsNumber(log(10.0)), DontDelete
| DontEnum
| ReadOnly
);
92 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete
| DontEnum
| ReadOnly
);
93 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "LOG10E"), jsNumber(0.4342944819032518), DontDelete
| DontEnum
| ReadOnly
);
94 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "PI"), jsNumber(piDouble
), DontDelete
| DontEnum
| ReadOnly
);
95 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete
| DontEnum
| ReadOnly
);
96 putDirectWithoutTransition(vm
, Identifier::fromString(&vm
, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete
| DontEnum
| ReadOnly
);
98 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "abs"), 1, mathProtoFuncAbs
, AbsIntrinsic
, DontEnum
| Function
);
99 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "acos"), 1, mathProtoFuncACos
, NoIntrinsic
, DontEnum
| Function
);
100 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "asin"), 1, mathProtoFuncASin
, NoIntrinsic
, DontEnum
| Function
);
101 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "atan"), 1, mathProtoFuncATan
, NoIntrinsic
, DontEnum
| Function
);
102 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "acosh"), 1, mathProtoFuncACosh
, NoIntrinsic
, DontEnum
| Function
);
103 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "asinh"), 1, mathProtoFuncASinh
, NoIntrinsic
, DontEnum
| Function
);
104 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "atanh"), 1, mathProtoFuncATanh
, NoIntrinsic
, DontEnum
| Function
);
105 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "atan2"), 2, mathProtoFuncATan2
, NoIntrinsic
, DontEnum
| Function
);
106 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "cbrt"), 1, mathProtoFuncCbrt
, NoIntrinsic
, DontEnum
| Function
);
107 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "ceil"), 1, mathProtoFuncCeil
, CeilIntrinsic
, DontEnum
| Function
);
108 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "clz32"), 1, mathProtoFuncClz32
, Clz32Intrinsic
, DontEnum
| Function
);
109 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "cos"), 1, mathProtoFuncCos
, CosIntrinsic
, DontEnum
| Function
);
110 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "cosh"), 1, mathProtoFuncCosh
, NoIntrinsic
, DontEnum
| Function
);
111 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "exp"), 1, mathProtoFuncExp
, ExpIntrinsic
, DontEnum
| Function
);
112 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "expm1"), 1, mathProtoFuncExpm1
, NoIntrinsic
, DontEnum
| Function
);
113 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "floor"), 1, mathProtoFuncFloor
, FloorIntrinsic
, DontEnum
| Function
);
114 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "fround"), 1, mathProtoFuncFround
, FRoundIntrinsic
, DontEnum
| Function
);
115 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "hypot"), 2, mathProtoFuncHypot
, NoIntrinsic
, DontEnum
| Function
);
116 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "log"), 1, mathProtoFuncLog
, LogIntrinsic
, DontEnum
| Function
);
117 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "log10"), 1, mathProtoFuncLog10
, NoIntrinsic
, DontEnum
| Function
);
118 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "log1p"), 1, mathProtoFuncLog1p
, NoIntrinsic
, DontEnum
| Function
);
119 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "log2"), 1, mathProtoFuncLog2
, NoIntrinsic
, DontEnum
| Function
);
120 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "max"), 2, mathProtoFuncMax
, MaxIntrinsic
, DontEnum
| Function
);
121 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "min"), 2, mathProtoFuncMin
, MinIntrinsic
, DontEnum
| Function
);
122 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "pow"), 2, mathProtoFuncPow
, PowIntrinsic
, DontEnum
| Function
);
123 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "random"), 0, mathProtoFuncRandom
, NoIntrinsic
, DontEnum
| Function
);
124 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "round"), 1, mathProtoFuncRound
, RoundIntrinsic
, DontEnum
| Function
);
125 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "sign"), 1, mathProtoFuncSign
, NoIntrinsic
, DontEnum
| Function
);
126 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "sin"), 1, mathProtoFuncSin
, SinIntrinsic
, DontEnum
| Function
);
127 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "sinh"), 1, mathProtoFuncSinh
, NoIntrinsic
, DontEnum
| Function
);
128 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "sqrt"), 1, mathProtoFuncSqrt
, SqrtIntrinsic
, DontEnum
| Function
);
129 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "tan"), 1, mathProtoFuncTan
, NoIntrinsic
, DontEnum
| Function
);
130 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "tanh"), 1, mathProtoFuncTanh
, NoIntrinsic
, DontEnum
| Function
);
131 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "trunc"), 1, mathProtoFuncTrunc
, NoIntrinsic
, DontEnum
| Function
);
132 putDirectNativeFunctionWithoutTransition(vm
, globalObject
, Identifier::fromString(&vm
, "imul"), 2, mathProtoFuncIMul
, IMulIntrinsic
, DontEnum
| Function
);
135 // ------------------------------ Functions --------------------------------
137 EncodedJSValue JSC_HOST_CALL
mathProtoFuncAbs(ExecState
* exec
)
139 return JSValue::encode(jsNumber(fabs(exec
->argument(0).toNumber(exec
))));
142 EncodedJSValue JSC_HOST_CALL
mathProtoFuncACos(ExecState
* exec
)
144 return JSValue::encode(jsDoubleNumber(acos(exec
->argument(0).toNumber(exec
))));
147 EncodedJSValue JSC_HOST_CALL
mathProtoFuncASin(ExecState
* exec
)
149 return JSValue::encode(jsDoubleNumber(asin(exec
->argument(0).toNumber(exec
))));
152 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATan(ExecState
* exec
)
154 return JSValue::encode(jsDoubleNumber(atan(exec
->argument(0).toNumber(exec
))));
157 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATan2(ExecState
* exec
)
159 double arg0
= exec
->argument(0).toNumber(exec
);
160 double arg1
= exec
->argument(1).toNumber(exec
);
161 return JSValue::encode(jsDoubleNumber(atan2(arg0
, arg1
)));
164 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCeil(ExecState
* exec
)
166 return JSValue::encode(jsNumber(ceil(exec
->argument(0).toNumber(exec
))));
169 EncodedJSValue JSC_HOST_CALL
mathProtoFuncClz32(ExecState
* exec
)
171 uint32_t value
= exec
->argument(0).toUInt32(exec
);
172 if (exec
->hadException())
173 return JSValue::encode(jsNull());
174 return JSValue::encode(JSValue(clz32(value
)));
177 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCos(ExecState
* exec
)
179 return JSValue::encode(jsDoubleNumber(cos(exec
->argument(0).toNumber(exec
))));
182 EncodedJSValue JSC_HOST_CALL
mathProtoFuncExp(ExecState
* exec
)
184 return JSValue::encode(jsDoubleNumber(exp(exec
->argument(0).toNumber(exec
))));
187 EncodedJSValue JSC_HOST_CALL
mathProtoFuncFloor(ExecState
* exec
)
189 return JSValue::encode(jsNumber(floor(exec
->argument(0).toNumber(exec
))));
192 EncodedJSValue JSC_HOST_CALL
mathProtoFuncHypot(ExecState
* exec
)
194 unsigned argsCount
= exec
->argumentCount();
196 Vector
<double, 8> args
;
197 args
.reserveInitialCapacity(argsCount
);
198 for (unsigned i
= 0; i
< argsCount
; ++i
) {
199 args
.uncheckedAppend(exec
->uncheckedArgument(i
).toNumber(exec
));
200 if (exec
->hadException())
201 return JSValue::encode(jsNull());
202 if (std::isinf(args
[i
]))
203 return JSValue::encode(jsDoubleNumber(+std::numeric_limits
<double>::infinity()));
204 max
= std::max(fabs(args
[i
]), max
);
208 // Kahan summation algorithm significantly reduces the numerical error in the total obtained.
210 double compensation
= 0;
211 for (double argument
: args
) {
212 double scaledArgument
= argument
/ max
;
213 double summand
= scaledArgument
* scaledArgument
- compensation
;
214 double preliminary
= sum
+ summand
;
215 compensation
= (preliminary
- sum
) - summand
;
218 return JSValue::encode(jsDoubleNumber(sqrt(sum
) * max
));
221 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog(ExecState
* exec
)
223 return JSValue::encode(jsDoubleNumber(log(exec
->argument(0).toNumber(exec
))));
226 EncodedJSValue JSC_HOST_CALL
mathProtoFuncMax(ExecState
* exec
)
228 unsigned argsCount
= exec
->argumentCount();
229 double result
= -std::numeric_limits
<double>::infinity();
230 for (unsigned k
= 0; k
< argsCount
; ++k
) {
231 double val
= exec
->uncheckedArgument(k
).toNumber(exec
);
232 if (std::isnan(val
)) {
234 } else if (val
> result
|| (!val
&& !result
&& !std::signbit(val
)))
237 return JSValue::encode(jsNumber(result
));
240 EncodedJSValue JSC_HOST_CALL
mathProtoFuncMin(ExecState
* exec
)
242 unsigned argsCount
= exec
->argumentCount();
243 double result
= +std::numeric_limits
<double>::infinity();
244 for (unsigned k
= 0; k
< argsCount
; ++k
) {
245 double val
= exec
->uncheckedArgument(k
).toNumber(exec
);
246 if (std::isnan(val
)) {
248 } else if (val
< result
|| (!val
&& !result
&& std::signbit(val
)))
251 return JSValue::encode(jsNumber(result
));
254 EncodedJSValue JSC_HOST_CALL
mathProtoFuncPow(ExecState
* exec
)
258 double arg
= exec
->argument(0).toNumber(exec
);
259 double arg2
= exec
->argument(1).toNumber(exec
);
261 return JSValue::encode(JSValue(operationMathPow(arg
, arg2
)));
264 EncodedJSValue JSC_HOST_CALL
mathProtoFuncRandom(ExecState
* exec
)
266 return JSValue::encode(jsDoubleNumber(exec
->lexicalGlobalObject()->weakRandomNumber()));
269 EncodedJSValue JSC_HOST_CALL
mathProtoFuncRound(ExecState
* exec
)
271 return JSValue::encode(jsNumber(jsRound(exec
->argument(0).toNumber(exec
))));
274 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSign(ExecState
* exec
)
276 double arg
= exec
->argument(0).toNumber(exec
);
278 return JSValue::encode(jsNaN());
280 return JSValue::encode(std::signbit(arg
) ? jsNumber(-0.0) : jsNumber(0));
281 return JSValue::encode(jsNumber(std::signbit(arg
) ? -1 : 1));
284 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSin(ExecState
* exec
)
286 return JSValue::encode(jsDoubleNumber(sin(exec
->argument(0).toNumber(exec
))));
289 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSqrt(ExecState
* exec
)
291 return JSValue::encode(jsDoubleNumber(sqrt(exec
->argument(0).toNumber(exec
))));
294 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTan(ExecState
* exec
)
296 return JSValue::encode(jsDoubleNumber(tan(exec
->argument(0).toNumber(exec
))));
299 EncodedJSValue JSC_HOST_CALL
mathProtoFuncIMul(ExecState
* exec
)
301 int32_t left
= exec
->argument(0).toInt32(exec
);
302 if (exec
->hadException())
303 return JSValue::encode(jsNull());
304 int32_t right
= exec
->argument(1).toInt32(exec
);
305 return JSValue::encode(jsNumber(left
* right
));
308 EncodedJSValue JSC_HOST_CALL
mathProtoFuncACosh(ExecState
* exec
)
310 return JSValue::encode(jsDoubleNumber(acosh(exec
->argument(0).toNumber(exec
))));
313 EncodedJSValue JSC_HOST_CALL
mathProtoFuncASinh(ExecState
* exec
)
315 return JSValue::encode(jsDoubleNumber(asinh(exec
->argument(0).toNumber(exec
))));
318 EncodedJSValue JSC_HOST_CALL
mathProtoFuncATanh(ExecState
* exec
)
320 return JSValue::encode(jsDoubleNumber(atanh(exec
->argument(0).toNumber(exec
))));
323 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCbrt(ExecState
* exec
)
325 return JSValue::encode(jsDoubleNumber(cbrt(exec
->argument(0).toNumber(exec
))));
328 EncodedJSValue JSC_HOST_CALL
mathProtoFuncCosh(ExecState
* exec
)
330 return JSValue::encode(jsDoubleNumber(cosh(exec
->argument(0).toNumber(exec
))));
333 EncodedJSValue JSC_HOST_CALL
mathProtoFuncExpm1(ExecState
* exec
)
335 return JSValue::encode(jsDoubleNumber(expm1(exec
->argument(0).toNumber(exec
))));
338 EncodedJSValue JSC_HOST_CALL
mathProtoFuncFround(ExecState
* exec
)
340 return JSValue::encode(jsDoubleNumber(static_cast<float>(exec
->argument(0).toNumber(exec
))));
343 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog1p(ExecState
* exec
)
345 double value
= exec
->argument(0).toNumber(exec
);
347 return JSValue::encode(jsDoubleNumber(value
));
348 return JSValue::encode(jsDoubleNumber(log1p(value
)));
351 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog10(ExecState
* exec
)
353 return JSValue::encode(jsDoubleNumber(log10(exec
->argument(0).toNumber(exec
))));
356 EncodedJSValue JSC_HOST_CALL
mathProtoFuncLog2(ExecState
* exec
)
358 return JSValue::encode(jsDoubleNumber(log2(exec
->argument(0).toNumber(exec
))));
361 EncodedJSValue JSC_HOST_CALL
mathProtoFuncSinh(ExecState
* exec
)
363 return JSValue::encode(jsDoubleNumber(sinh(exec
->argument(0).toNumber(exec
))));
366 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTanh(ExecState
* exec
)
368 return JSValue::encode(jsDoubleNumber(tanh(exec
->argument(0).toNumber(exec
))));
371 EncodedJSValue JSC_HOST_CALL
mathProtoFuncTrunc(ExecState
*exec
)
373 return JSValue::encode(jsNumber(exec
->argument(0).toIntegerPreserveNaN(exec
)));