]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/MathObject.cpp
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / runtime / MathObject.cpp
1 /*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2007, 2008, 2013 Apple Inc. All Rights Reserved.
4 *
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.
9 *
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.
14 *
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
18 *
19 */
20
21 #include "config.h"
22 #include "MathObject.h"
23
24 #include "Lookup.h"
25 #include "ObjectPrototype.h"
26 #include "JSCInlines.h"
27 #include <time.h>
28 #include <wtf/Assertions.h>
29 #include <wtf/MathExtras.h>
30 #include <wtf/RandomNumber.h>
31 #include <wtf/RandomNumberSeed.h>
32 #include <wtf/Vector.h>
33
34 namespace JSC {
35
36 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(MathObject);
37
38 static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
39 static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
40 static EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState*);
41 static EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*);
42 static EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState*);
43 static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*);
44 static EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState*);
45 static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
46 static EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*);
47 static EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
48 static EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
49 static EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*);
50 static EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
51 static EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
56 static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*);
57 static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*);
58 static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState*);
59 static EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*);
60 static EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*);
61 static EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*);
62 static EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*);
63 static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*);
64 static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
65 static EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState*);
66 static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
67 static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
68 static EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*);
69 static EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*);
70 static EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*);
71
72 }
73
74 namespace JSC {
75
76 const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MathObject) };
77
78 MathObject::MathObject(VM& vm, Structure* structure)
79 : JSNonFinalObject(vm, structure)
80 {
81 }
82
83 void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
84 {
85 Base::finishCreation(vm);
86 ASSERT(inherits(info()));
87
88 putDirectWithoutTransition(vm, Identifier(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
89 putDirectWithoutTransition(vm, Identifier(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
90 putDirectWithoutTransition(vm, Identifier(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
91 putDirectWithoutTransition(vm, Identifier(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
92 putDirectWithoutTransition(vm, Identifier(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly);
93 putDirectWithoutTransition(vm, Identifier(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
94 putDirectWithoutTransition(vm, Identifier(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
95 putDirectWithoutTransition(vm, Identifier(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
96
97 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum | Function);
98 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum | Function);
99 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum | Function);
100 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum | Function);
101 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum | Function);
102 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum | Function);
103 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum | Function);
104 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function);
105 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum | Function);
106 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function);
107 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function);
108 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum | Function);
109 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function);
110 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum | Function);
111 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function);
112 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "fround"), 1, mathProtoFuncFround, FRoundIntrinsic, DontEnum | Function);
113 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "hypot"), 2, mathProtoFuncHypot, NoIntrinsic, DontEnum | Function);
114 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function);
115 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum | Function);
116 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum | Function);
117 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum | Function);
118 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum | Function);
119 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum | Function);
120 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum | Function);
121 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "random"), 0, mathProtoFuncRandom, NoIntrinsic, DontEnum | Function);
122 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum | Function);
123 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum | Function);
124 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum | Function);
125 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum | Function);
126 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum | Function);
127 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum | Function);
128 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum | Function);
129 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "imul"), 1, mathProtoFuncIMul, IMulIntrinsic, DontEnum | Function);
130 }
131
132 // ------------------------------ Functions --------------------------------
133
134 EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec)
135 {
136 return JSValue::encode(jsNumber(fabs(exec->argument(0).toNumber(exec))));
137 }
138
139 EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec)
140 {
141 return JSValue::encode(jsDoubleNumber(acos(exec->argument(0).toNumber(exec))));
142 }
143
144 EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec)
145 {
146 return JSValue::encode(jsDoubleNumber(asin(exec->argument(0).toNumber(exec))));
147 }
148
149 EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec)
150 {
151 return JSValue::encode(jsDoubleNumber(atan(exec->argument(0).toNumber(exec))));
152 }
153
154 EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec)
155 {
156 double arg0 = exec->argument(0).toNumber(exec);
157 double arg1 = exec->argument(1).toNumber(exec);
158 return JSValue::encode(jsDoubleNumber(atan2(arg0, arg1)));
159 }
160
161 EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec)
162 {
163 return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec))));
164 }
165
166 EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
167 {
168 return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
169 }
170
171 EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec)
172 {
173 return JSValue::encode(jsDoubleNumber(exp(exec->argument(0).toNumber(exec))));
174 }
175
176 EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec)
177 {
178 return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec))));
179 }
180
181 EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec)
182 {
183 unsigned argsCount = exec->argumentCount();
184 double max = 0;
185 Vector<double, 8> args;
186 args.reserveInitialCapacity(argsCount);
187 for (unsigned i = 0; i < argsCount; ++i) {
188 args.uncheckedAppend(exec->uncheckedArgument(i).toNumber(exec));
189 if (exec->hadException())
190 return JSValue::encode(jsNull());
191 if (std::isinf(args[i]))
192 return JSValue::encode(jsDoubleNumber(+std::numeric_limits<double>::infinity()));
193 max = std::max(fabs(args[i]), max);
194 }
195 if (!max)
196 max = 1;
197 // Kahan summation algorithm significantly reduces the numerical error in the total obtained.
198 double sum = 0;
199 double compensation = 0;
200 for (double argument : args) {
201 double scaledArgument = argument / max;
202 double summand = scaledArgument * scaledArgument - compensation;
203 double preliminary = sum + summand;
204 compensation = (preliminary - sum) - summand;
205 sum = preliminary;
206 }
207 return JSValue::encode(jsDoubleNumber(sqrt(sum) * max));
208 }
209
210 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
211 {
212 return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));
213 }
214
215 EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec)
216 {
217 unsigned argsCount = exec->argumentCount();
218 double result = -std::numeric_limits<double>::infinity();
219 for (unsigned k = 0; k < argsCount; ++k) {
220 double val = exec->uncheckedArgument(k).toNumber(exec);
221 if (std::isnan(val)) {
222 result = PNaN;
223 } else if (val > result || (!val && !result && !std::signbit(val)))
224 result = val;
225 }
226 return JSValue::encode(jsNumber(result));
227 }
228
229 EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec)
230 {
231 unsigned argsCount = exec->argumentCount();
232 double result = +std::numeric_limits<double>::infinity();
233 for (unsigned k = 0; k < argsCount; ++k) {
234 double val = exec->uncheckedArgument(k).toNumber(exec);
235 if (std::isnan(val)) {
236 result = PNaN;
237 } else if (val < result || (!val && !result && std::signbit(val)))
238 result = val;
239 }
240 return JSValue::encode(jsNumber(result));
241 }
242
243 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
244
245 static double fdlibmPow(double x, double y);
246
247 static ALWAYS_INLINE bool isDenormal(double x)
248 {
249 static const uint64_t signbit = 0x8000000000000000ULL;
250 static const uint64_t minNormal = 0x0001000000000000ULL;
251 return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1;
252 }
253
254 static ALWAYS_INLINE bool isEdgeCase(double x)
255 {
256 static const uint64_t signbit = 0x8000000000000000ULL;
257 static const uint64_t infinity = 0x7fffffffffffffffULL;
258 return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1;
259 }
260
261 static ALWAYS_INLINE double mathPow(double x, double y)
262 {
263 if (!isDenormal(x) && !isDenormal(y)) {
264 double libmResult = pow(x,y);
265 if (libmResult || isEdgeCase(x) || isEdgeCase(y))
266 return libmResult;
267 }
268 return fdlibmPow(x,y);
269 }
270
271 #else
272
273 ALWAYS_INLINE double mathPow(double x, double y)
274 {
275 return pow(x, y);
276 }
277
278 #endif
279
280 EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
281 {
282 // ECMA 15.8.2.1.13
283
284 double arg = exec->argument(0).toNumber(exec);
285 double arg2 = exec->argument(1).toNumber(exec);
286
287 if (std::isnan(arg2))
288 return JSValue::encode(jsNaN());
289 if (std::isinf(arg2) && fabs(arg) == 1)
290 return JSValue::encode(jsNaN());
291 return JSValue::encode(jsNumber(mathPow(arg, arg2)));
292 }
293
294 EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
295 {
296 return JSValue::encode(jsDoubleNumber(exec->lexicalGlobalObject()->weakRandomNumber()));
297 }
298
299 EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
300 {
301 double arg = exec->argument(0).toNumber(exec);
302 double integer = ceil(arg);
303 return JSValue::encode(jsNumber(integer - (integer - arg > 0.5)));
304 }
305
306 EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
307 {
308 return JSValue::encode(jsDoubleNumber(sin(exec->argument(0).toNumber(exec))));
309 }
310
311 EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
312 {
313 return JSValue::encode(jsDoubleNumber(sqrt(exec->argument(0).toNumber(exec))));
314 }
315
316 EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec)
317 {
318 return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec))));
319 }
320
321 EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState* exec)
322 {
323 int32_t left = exec->argument(0).toInt32(exec);
324 if (exec->hadException())
325 return JSValue::encode(jsNull());
326 int32_t right = exec->argument(1).toInt32(exec);
327 return JSValue::encode(jsNumber(left * right));
328 }
329
330 EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState* exec)
331 {
332 return JSValue::encode(jsDoubleNumber(acosh(exec->argument(0).toNumber(exec))));
333 }
334
335 EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState* exec)
336 {
337 return JSValue::encode(jsDoubleNumber(asinh(exec->argument(0).toNumber(exec))));
338 }
339
340 EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState* exec)
341 {
342 return JSValue::encode(jsDoubleNumber(atanh(exec->argument(0).toNumber(exec))));
343 }
344
345 EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState* exec)
346 {
347 return JSValue::encode(jsDoubleNumber(cbrt(exec->argument(0).toNumber(exec))));
348 }
349
350 EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState* exec)
351 {
352 return JSValue::encode(jsDoubleNumber(cosh(exec->argument(0).toNumber(exec))));
353 }
354
355 EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState* exec)
356 {
357 return JSValue::encode(jsDoubleNumber(expm1(exec->argument(0).toNumber(exec))));
358 }
359
360 EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState* exec)
361 {
362 return JSValue::encode(jsDoubleNumber(static_cast<float>(exec->argument(0).toNumber(exec))));
363 }
364
365 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState* exec)
366 {
367 double value = exec->argument(0).toNumber(exec);
368 if (value == 0)
369 return JSValue::encode(jsDoubleNumber(value));
370 return JSValue::encode(jsDoubleNumber(log1p(value)));
371 }
372
373 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState* exec)
374 {
375 return JSValue::encode(jsDoubleNumber(log10(exec->argument(0).toNumber(exec))));
376 }
377
378 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState* exec)
379 {
380 return JSValue::encode(jsDoubleNumber(log2(exec->argument(0).toNumber(exec))));
381 }
382
383 EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState* exec)
384 {
385 return JSValue::encode(jsDoubleNumber(sinh(exec->argument(0).toNumber(exec))));
386 }
387
388 EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState* exec)
389 {
390 return JSValue::encode(jsDoubleNumber(tanh(exec->argument(0).toNumber(exec))));
391 }
392
393 EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*exec)
394 {
395 return JSValue::encode(jsNumber(exec->argument(0).toIntegerPreserveNaN(exec)));
396 }
397
398
399 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
400
401 // The following code is taken from netlib.org:
402 // http://www.netlib.org/fdlibm/fdlibm.h
403 // http://www.netlib.org/fdlibm/e_pow.c
404 // http://www.netlib.org/fdlibm/s_scalbn.c
405 //
406 // And was originally distributed under the following license:
407
408 /*
409 * ====================================================
410 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
411 *
412 * Developed at SunSoft, a Sun Microsystems, Inc. business.
413 * Permission to use, copy, modify, and distribute this
414 * software is freely granted, provided that this notice
415 * is preserved.
416 * ====================================================
417 */
418 /*
419 * ====================================================
420 * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
421 *
422 * Permission to use, copy, modify, and distribute this
423 * software is freely granted, provided that this notice
424 * is preserved.
425 * ====================================================
426 */
427
428 /* __ieee754_pow(x,y) return x**y
429 *
430 * n
431 * Method: Let x = 2 * (1+f)
432 * 1. Compute and return log2(x) in two pieces:
433 * log2(x) = w1 + w2,
434 * where w1 has 53-24 = 29 bit trailing zeros.
435 * 2. Perform y*log2(x) = n+y' by simulating muti-precision
436 * arithmetic, where |y'|<=0.5.
437 * 3. Return x**y = 2**n*exp(y'*log2)
438 *
439 * Special cases:
440 * 1. (anything) ** 0 is 1
441 * 2. (anything) ** 1 is itself
442 * 3. (anything) ** NAN is NAN
443 * 4. NAN ** (anything except 0) is NAN
444 * 5. +-(|x| > 1) ** +INF is +INF
445 * 6. +-(|x| > 1) ** -INF is +0
446 * 7. +-(|x| < 1) ** +INF is +0
447 * 8. +-(|x| < 1) ** -INF is +INF
448 * 9. +-1 ** +-INF is NAN
449 * 10. +0 ** (+anything except 0, NAN) is +0
450 * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
451 * 12. +0 ** (-anything except 0, NAN) is +INF
452 * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
453 * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
454 * 15. +INF ** (+anything except 0,NAN) is +INF
455 * 16. +INF ** (-anything except 0,NAN) is +0
456 * 17. -INF ** (anything) = -0 ** (-anything)
457 * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
458 * 19. (-anything except 0 and inf) ** (non-integer) is NAN
459 *
460 * Accuracy:
461 * pow(x,y) returns x**y nearly rounded. In particular
462 * pow(integer,integer)
463 * always returns the correct integer provided it is
464 * representable.
465 *
466 * Constants :
467 * The hexadecimal values are the intended ones for the following
468 * constants. The decimal values may be used, provided that the
469 * compiler will convert from decimal to binary accurately enough
470 * to produce the hexadecimal values shown.
471 */
472
473 #define __HI(x) *(1+(int*)&x)
474 #define __LO(x) *(int*)&x
475
476 static const double
477 bp[] = {1.0, 1.5,},
478 dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
479 dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
480 zero = 0.0,
481 one = 1.0,
482 two = 2.0,
483 two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
484 huge = 1.0e300,
485 tiny = 1.0e-300,
486 /* for scalbn */
487 two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
488 twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
489 /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
490 L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
491 L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
492 L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
493 L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
494 L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
495 L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
496 P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
497 P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
498 P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
499 P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
500 P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
501 lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
502 lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
503 lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
504 ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
505 cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
506 cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
507 cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
508 ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
509 ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
510 ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
511
512 inline double fdlibmScalbn (double x, int n)
513 {
514 int k,hx,lx;
515 hx = __HI(x);
516 lx = __LO(x);
517 k = (hx&0x7ff00000)>>20; /* extract exponent */
518 if (k==0) { /* 0 or subnormal x */
519 if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
520 x *= two54;
521 hx = __HI(x);
522 k = ((hx&0x7ff00000)>>20) - 54;
523 if (n< -50000) return tiny*x; /*underflow*/
524 }
525 if (k==0x7ff) return x+x; /* NaN or Inf */
526 k = k+n;
527 if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
528 if (k > 0) /* normal result */
529 {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
530 if (k <= -54) {
531 if (n > 50000) /* in case integer overflow in n+k */
532 return huge*copysign(huge,x); /*overflow*/
533 else return tiny*copysign(tiny,x); /*underflow*/
534 }
535 k += 54; /* subnormal result */
536 __HI(x) = (hx&0x800fffff)|(k<<20);
537 return x*twom54;
538 }
539
540 double fdlibmPow(double x, double y)
541 {
542 double z,ax,z_h,z_l,p_h,p_l;
543 double y1,t1,t2,r,s,t,u,v,w;
544 int i0,i1,i,j,k,yisint,n;
545 int hx,hy,ix,iy;
546 unsigned lx,ly;
547
548 i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
549 hx = __HI(x); lx = __LO(x);
550 hy = __HI(y); ly = __LO(y);
551 ix = hx&0x7fffffff; iy = hy&0x7fffffff;
552
553 /* y==zero: x**0 = 1 */
554 if((iy|ly)==0) return one;
555
556 /* +-NaN return x+y */
557 if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
558 iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
559 return x+y;
560
561 /* determine if y is an odd int when x < 0
562 * yisint = 0 ... y is not an integer
563 * yisint = 1 ... y is an odd int
564 * yisint = 2 ... y is an even int
565 */
566 yisint = 0;
567 if(hx<0) {
568 if(iy>=0x43400000) yisint = 2; /* even integer y */
569 else if(iy>=0x3ff00000) {
570 k = (iy>>20)-0x3ff; /* exponent */
571 if(k>20) {
572 j = ly>>(52-k);
573 if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1);
574 } else if(ly==0) {
575 j = iy>>(20-k);
576 if((j<<(20-k))==iy) yisint = 2-(j&1);
577 }
578 }
579 }
580
581 /* special value of y */
582 if(ly==0) {
583 if (iy==0x7ff00000) { /* y is +-inf */
584 if(((ix-0x3ff00000)|lx)==0)
585 return y - y; /* inf**+-1 is NaN */
586 else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
587 return (hy>=0)? y: zero;
588 else /* (|x|<1)**-,+inf = inf,0 */
589 return (hy<0)?-y: zero;
590 }
591 if(iy==0x3ff00000) { /* y is +-1 */
592 if(hy<0) return one/x; else return x;
593 }
594 if(hy==0x40000000) return x*x; /* y is 2 */
595 if(hy==0x3fe00000) { /* y is 0.5 */
596 if(hx>=0) /* x >= +0 */
597 return sqrt(x);
598 }
599 }
600
601 ax = fabs(x);
602 /* special value of x */
603 if(lx==0) {
604 if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
605 z = ax; /*x is +-0,+-inf,+-1*/
606 if(hy<0) z = one/z; /* z = (1/|x|) */
607 if(hx<0) {
608 if(((ix-0x3ff00000)|yisint)==0) {
609 z = (z-z)/(z-z); /* (-1)**non-int is NaN */
610 } else if(yisint==1)
611 z = -z; /* (x<0)**odd = -(|x|**odd) */
612 }
613 return z;
614 }
615 }
616
617 n = (hx>>31)+1;
618
619 /* (x<0)**(non-int) is NaN */
620 if((n|yisint)==0) return (x-x)/(x-x);
621
622 s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
623 if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
624
625 /* |y| is huge */
626 if(iy>0x41e00000) { /* if |y| > 2**31 */
627 if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
628 if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
629 if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
630 }
631 /* over/underflow if x is not close to one */
632 if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
633 if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
634 /* now |1-x| is tiny <= 2**-20, suffice to compute
635 log(x) by x-x^2/2+x^3/3-x^4/4 */
636 t = ax-one; /* t has 20 trailing zeros */
637 w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
638 u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
639 v = t*ivln2_l-w*ivln2;
640 t1 = u+v;
641 __LO(t1) = 0;
642 t2 = v-(t1-u);
643 } else {
644 double ss,s2,s_h,s_l,t_h,t_l;
645 n = 0;
646 /* take care subnormal number */
647 if(ix<0x00100000)
648 {ax *= two53; n -= 53; ix = __HI(ax); }
649 n += ((ix)>>20)-0x3ff;
650 j = ix&0x000fffff;
651 /* determine interval */
652 ix = j|0x3ff00000; /* normalize ix */
653 if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
654 else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
655 else {k=0;n+=1;ix -= 0x00100000;}
656 __HI(ax) = ix;
657
658 /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
659 u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
660 v = one/(ax+bp[k]);
661 ss = u*v;
662 s_h = ss;
663 __LO(s_h) = 0;
664 /* t_h=ax+bp[k] High */
665 t_h = zero;
666 __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
667 t_l = ax - (t_h-bp[k]);
668 s_l = v*((u-s_h*t_h)-s_h*t_l);
669 /* compute log(ax) */
670 s2 = ss*ss;
671 r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
672 r += s_l*(s_h+ss);
673 s2 = s_h*s_h;
674 t_h = 3.0+s2+r;
675 __LO(t_h) = 0;
676 t_l = r-((t_h-3.0)-s2);
677 /* u+v = ss*(1+...) */
678 u = s_h*t_h;
679 v = s_l*t_h+t_l*ss;
680 /* 2/(3log2)*(ss+...) */
681 p_h = u+v;
682 __LO(p_h) = 0;
683 p_l = v-(p_h-u);
684 z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
685 z_l = cp_l*p_h+p_l*cp+dp_l[k];
686 /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
687 t = (double)n;
688 t1 = (((z_h+z_l)+dp_h[k])+t);
689 __LO(t1) = 0;
690 t2 = z_l-(((t1-t)-dp_h[k])-z_h);
691 }
692
693 /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
694 y1 = y;
695 __LO(y1) = 0;
696 p_l = (y-y1)*t1+y*t2;
697 p_h = y1*t1;
698 z = p_l+p_h;
699 j = __HI(z);
700 i = __LO(z);
701 if (j>=0x40900000) { /* z >= 1024 */
702 if(((j-0x40900000)|i)!=0) /* if z > 1024 */
703 return s*huge*huge; /* overflow */
704 else {
705 if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
706 }
707 } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
708 if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
709 return s*tiny*tiny; /* underflow */
710 else {
711 if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
712 }
713 }
714 /*
715 * compute 2**(p_h+p_l)
716 */
717 i = j&0x7fffffff;
718 k = (i>>20)-0x3ff;
719 n = 0;
720 if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
721 n = j+(0x00100000>>(k+1));
722 k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
723 t = zero;
724 __HI(t) = (n&~(0x000fffff>>k));
725 n = ((n&0x000fffff)|0x00100000)>>(20-k);
726 if(j<0) n = -n;
727 p_h -= t;
728 }
729 t = p_l+p_h;
730 __LO(t) = 0;
731 u = t*lg2_h;
732 v = (p_l-(t-p_h))*lg2+t*lg2_l;
733 z = u+v;
734 w = v-(z-u);
735 t = z*z;
736 t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
737 r = (z*t1)/(t1-two)-(w+z*w);
738 z = one-(r-z);
739 j = __HI(z);
740 j += (n<<20);
741 if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */
742 else __HI(z) += (n<<20);
743 return s*z;
744 }
745
746 #endif
747
748 } // namespace JSC