summaryrefslogtreecommitdiff
path: root/deps/v8/src/math.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/math.js')
-rw-r--r--deps/v8/src/math.js313
1 files changed, 211 insertions, 102 deletions
diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js
index f8738b5f8..13cdb31cd 100644
--- a/deps/v8/src/math.js
+++ b/deps/v8/src/math.js
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+"use strict";
+
// This file relies on the fact that the following declarations have been made
// in runtime.js:
// var $Object = global.Object;
@@ -28,24 +30,24 @@ function MathAbs(x) {
}
// ECMA 262 - 15.8.2.2
-function MathAcos(x) {
+function MathAcosJS(x) {
return %MathAcos(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.3
-function MathAsin(x) {
+function MathAsinJS(x) {
return %MathAsin(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.4
-function MathAtan(x) {
+function MathAtanJS(x) {
return %MathAtan(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.5
// The naming of y and x matches the spec, as does the order in which
// ToNumber (valueOf) is called.
-function MathAtan2(y, x) {
+function MathAtan2JS(y, x) {
return %MathAtan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x));
}
@@ -54,15 +56,9 @@ function MathCeil(x) {
return -MathFloor(-x);
}
-// ECMA 262 - 15.8.2.7
-function MathCos(x) {
- x = MathAbs(x); // Convert to number and get rid of -0.
- return TrigonometricInterpolation(x, 1);
-}
-
// ECMA 262 - 15.8.2.8
function MathExp(x) {
- return %MathExp(TO_NUMBER_INLINE(x));
+ return %MathExpRT(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.9
@@ -77,13 +73,13 @@ function MathFloor(x) {
// has to be -0, which wouldn't be the case with the shift.
return TO_UINT32(x);
} else {
- return %MathFloor(x);
+ return %MathFloorRT(x);
}
}
// ECMA 262 - 15.8.2.10
function MathLog(x) {
- return %_MathLog(TO_NUMBER_INLINE(x));
+ return %_MathLogRT(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.11
@@ -162,21 +158,9 @@ function MathRound(x) {
return %RoundNumber(TO_NUMBER_INLINE(x));
}
-// ECMA 262 - 15.8.2.16
-function MathSin(x) {
- x = x * 1; // Convert to number and deal with -0.
- if (%_IsMinusZero(x)) return x;
- return TrigonometricInterpolation(x, 0);
-}
-
// ECMA 262 - 15.8.2.17
function MathSqrt(x) {
- return %_MathSqrt(TO_NUMBER_INLINE(x));
-}
-
-// ECMA 262 - 15.8.2.18
-function MathTan(x) {
- return MathSin(x) / MathCos(x);
+ return %_MathSqrtRT(TO_NUMBER_INLINE(x));
}
// Non-standard extension.
@@ -184,72 +168,183 @@ function MathImul(x, y) {
return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
}
+// ES6 draft 09-27-13, section 20.2.2.28.
+function MathSign(x) {
+ x = TO_NUMBER_INLINE(x);
+ if (x > 0) return 1;
+ if (x < 0) return -1;
+ if (x === 0) return x;
+ return NAN;
+}
-var kInversePiHalf = 0.636619772367581343; // 2 / pi
-var kInversePiHalfS26 = 9.48637384723993156e-9; // 2 / pi / (2^26)
-var kS26 = 1 << 26;
-var kTwoStepThreshold = 1 << 27;
-// pi / 2 rounded up
-var kPiHalf = 1.570796326794896780; // 0x192d4454fb21f93f
-// We use two parts for pi/2 to emulate a higher precision.
-// pi_half_1 only has 26 significant bits for mantissa.
-// Note that pi_half > pi_half_1 + pi_half_2
-var kPiHalf1 = 1.570796325802803040; // 0x00000054fb21f93f
-var kPiHalf2 = 9.920935796805404252e-10; // 0x3326a611460b113e
-
-var kSamples; // Initialized to a number during genesis.
-var kIndexConvert; // Initialized to kSamples / (pi/2) during genesis.
-var kSinTable; // Initialized to a Float64Array during genesis.
-var kCosXIntervalTable; // Initialized to a Float64Array during genesis.
-
-// This implements sine using the following algorithm.
-// 1) Multiplication takes care of to-number conversion.
-// 2) Reduce x to the first quadrant [0, pi/2].
-// Conveniently enough, in case of +/-Infinity, we get NaN.
-// Note that we try to use only 26 instead of 52 significant bits for
-// mantissa to avoid rounding errors when multiplying. For very large
-// input we therefore have additional steps.
-// 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
-// 4) Do a table lookup for the closest samples to the left and right of x.
-// 5) Find the derivatives at those sampling points by table lookup:
-// dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
-// 6) Use cubic spline interpolation to approximate sin(x).
-// 7) Negate the result if x was in the 3rd or 4th quadrant.
-// 8) Get rid of -0 by adding 0.
-function TrigonometricInterpolation(x, phase) {
- if (x < 0 || x > kPiHalf) {
- var multiple;
- while (x < -kTwoStepThreshold || x > kTwoStepThreshold) {
- // Let's assume this loop does not terminate.
- // All numbers x in each loop forms a set S.
- // (1) abs(x) > 2^27 for all x in S.
- // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
- // (3) multiple is rounded down in 2^26 steps, so the rounding error is
- // at most max(ulp, 2^26).
- // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
- // (1-pi/4)x
- // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
- // Note that this difference cannot be simply rounded off.
- // Set S cannot exist since (5) violates (1). Loop must terminate.
- multiple = MathFloor(x * kInversePiHalfS26) * kS26;
- x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
- }
- multiple = MathFloor(x * kInversePiHalf);
- x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
- phase += multiple;
+// ES6 draft 09-27-13, section 20.2.2.34.
+function MathTrunc(x) {
+ x = TO_NUMBER_INLINE(x);
+ if (x > 0) return MathFloor(x);
+ if (x < 0) return MathCeil(x);
+ if (x === 0) return x;
+ return NAN;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.30.
+function MathSinh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ // Idempotent for NaN, +/-0 and +/-Infinity.
+ if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
+ return (MathExp(x) - MathExp(-x)) / 2;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.12.
+function MathCosh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ if (!NUMBER_IS_FINITE(x)) return MathAbs(x);
+ return (MathExp(x) + MathExp(-x)) / 2;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.33.
+function MathTanh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ // Idempotent for +/-0.
+ if (x === 0) return x;
+ // Returns +/-1 for +/-Infinity.
+ if (!NUMBER_IS_FINITE(x)) return MathSign(x);
+ var exp1 = MathExp(x);
+ var exp2 = MathExp(-x);
+ return (exp1 - exp2) / (exp1 + exp2);
+}
+
+// ES6 draft 09-27-13, section 20.2.2.5.
+function MathAsinh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ // Idempotent for NaN, +/-0 and +/-Infinity.
+ if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
+ if (x > 0) return MathLog(x + MathSqrt(x * x + 1));
+ // This is to prevent numerical errors caused by large negative x.
+ return -MathLog(-x + MathSqrt(x * x + 1));
+}
+
+// ES6 draft 09-27-13, section 20.2.2.3.
+function MathAcosh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ if (x < 1) return NAN;
+ // Idempotent for NaN and +Infinity.
+ if (!NUMBER_IS_FINITE(x)) return x;
+ return MathLog(x + MathSqrt(x + 1) * MathSqrt(x - 1));
+}
+
+// ES6 draft 09-27-13, section 20.2.2.7.
+function MathAtanh(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ // Idempotent for +/-0.
+ if (x === 0) return x;
+ // Returns NaN for NaN and +/- Infinity.
+ if (!NUMBER_IS_FINITE(x)) return NAN;
+ return 0.5 * MathLog((1 + x) / (1 - x));
+}
+
+// ES6 draft 09-27-13, section 20.2.2.21.
+function MathLog10(x) {
+ return MathLog(x) * 0.434294481903251828; // log10(x) = log(x)/log(10).
+}
+
+
+// ES6 draft 09-27-13, section 20.2.2.22.
+function MathLog2(x) {
+ return MathLog(x) * 1.442695040888963407; // log2(x) = log(x)/log(2).
+}
+
+// ES6 draft 09-27-13, section 20.2.2.17.
+function MathHypot(x, y) { // Function length is 2.
+ // We may want to introduce fast paths for two arguments and when
+ // normalization to avoid overflow is not necessary. For now, we
+ // simply assume the general case.
+ var length = %_ArgumentsLength();
+ var args = new InternalArray(length);
+ var max = 0;
+ for (var i = 0; i < length; i++) {
+ var n = %_Arguments(i);
+ if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
+ if (n === INFINITY || n === -INFINITY) return INFINITY;
+ n = MathAbs(n);
+ if (n > max) max = n;
+ args[i] = n;
+ }
+
+ // Kahan summation to avoid rounding errors.
+ // Normalize the numbers to the largest one to avoid overflow.
+ if (max === 0) max = 1;
+ var sum = 0;
+ var compensation = 0;
+ for (var i = 0; i < length; i++) {
+ var n = args[i] / max;
+ var summand = n * n - compensation;
+ var preliminary = sum + summand;
+ compensation = (preliminary - sum) - summand;
+ sum = preliminary;
+ }
+ return MathSqrt(sum) * max;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.16.
+function MathFroundJS(x) {
+ return %MathFround(TO_NUMBER_INLINE(x));
+}
+
+// ES6 draft 07-18-14, section 20.2.2.11
+function MathClz32(x) {
+ x = ToUint32(TO_NUMBER_INLINE(x));
+ if (x == 0) return 32;
+ var result = 0;
+ // Binary search.
+ if ((x & 0xFFFF0000) === 0) { x <<= 16; result += 16; };
+ if ((x & 0xFF000000) === 0) { x <<= 8; result += 8; };
+ if ((x & 0xF0000000) === 0) { x <<= 4; result += 4; };
+ if ((x & 0xC0000000) === 0) { x <<= 2; result += 2; };
+ if ((x & 0x80000000) === 0) { x <<= 1; result += 1; };
+ return result;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.9.
+// Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm
+// Using initial approximation adapted from Kahan's cbrt and 4 iterations
+// of Newton's method.
+function MathCbrt(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ if (x == 0 || !NUMBER_IS_FINITE(x)) return x;
+ return x >= 0 ? CubeRoot(x) : -CubeRoot(-x);
+}
+
+macro NEWTON_ITERATION_CBRT(x, approx)
+ (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
+endmacro
+
+function CubeRoot(x) {
+ var approx_hi = MathFloor(%_DoubleHi(x) / 3) + 0x2A9F7893;
+ var approx = %_ConstructDouble(approx_hi, 0);
+ approx = NEWTON_ITERATION_CBRT(x, approx);
+ approx = NEWTON_ITERATION_CBRT(x, approx);
+ approx = NEWTON_ITERATION_CBRT(x, approx);
+ return NEWTON_ITERATION_CBRT(x, approx);
+}
+
+// ES6 draft 09-27-13, section 20.2.2.14.
+// Use Taylor series to approximate.
+// exp(x) - 1 at 0 == -1 + exp(0) + exp'(0)*x/1! + exp''(0)*x^2/2! + ...
+// == x/1! + x^2/2! + x^3/3! + ...
+// The closer x is to 0, the fewer terms are required.
+function MathExpm1(x) {
+ if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ var xabs = MathAbs(x);
+ if (xabs < 2E-7) {
+ return x * (1 + x * (1/2));
+ } else if (xabs < 6E-5) {
+ return x * (1 + x * (1/2 + x * (1/6)));
+ } else if (xabs < 2E-2) {
+ return x * (1 + x * (1/2 + x * (1/6 +
+ x * (1/24 + x * (1/120 + x * (1/720))))));
+ } else { // Use regular exp if not close enough to 0.
+ return MathExp(x) - 1;
}
- var double_index = x * kIndexConvert;
- if (phase & 1) double_index = kSamples - double_index;
- var index = double_index | 0;
- var t1 = double_index - index;
- var t2 = 1 - t1;
- var y1 = kSinTable[index];
- var y2 = kSinTable[index + 1];
- var dy = y2 - y1;
- return (t2 * y1 + t1 * y2 +
- t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 +
- (dy - kCosXIntervalTable[index + 1]) * t1))
- * (1 - (phase & 2)) + 0;
}
// -------------------------------------------------------------------
@@ -257,8 +352,8 @@ function TrigonometricInterpolation(x, phase) {
function SetUpMath() {
%CheckIsBootstrapping();
- %SetPrototype($Math, $Object.prototype);
- %SetProperty(global, "Math", $Math, DONT_ENUM);
+ %InternalSetPrototype($Math, $Object.prototype);
+ %AddNamedProperty(global, "Math", $Math, DONT_ENUM);
%FunctionSetInstanceClassName(MathConstructor, 'Math');
// Set up math constants.
@@ -282,31 +377,45 @@ function SetUpMath() {
InstallFunctions($Math, DONT_ENUM, $Array(
"random", MathRandom,
"abs", MathAbs,
- "acos", MathAcos,
- "asin", MathAsin,
- "atan", MathAtan,
+ "acos", MathAcosJS,
+ "asin", MathAsinJS,
+ "atan", MathAtanJS,
"ceil", MathCeil,
- "cos", MathCos,
+ "cos", MathCos, // implemented by third_party/fdlibm
"exp", MathExp,
"floor", MathFloor,
"log", MathLog,
"round", MathRound,
- "sin", MathSin,
+ "sin", MathSin, // implemented by third_party/fdlibm
"sqrt", MathSqrt,
- "tan", MathTan,
- "atan2", MathAtan2,
+ "tan", MathTan, // implemented by third_party/fdlibm
+ "atan2", MathAtan2JS,
"pow", MathPow,
"max", MathMax,
"min", MathMin,
- "imul", MathImul
+ "imul", MathImul,
+ "sign", MathSign,
+ "trunc", MathTrunc,
+ "sinh", MathSinh,
+ "cosh", MathCosh,
+ "tanh", MathTanh,
+ "asinh", MathAsinh,
+ "acosh", MathAcosh,
+ "atanh", MathAtanh,
+ "log10", MathLog10,
+ "log2", MathLog2,
+ "hypot", MathHypot,
+ "fround", MathFroundJS,
+ "clz32", MathClz32,
+ "cbrt", MathCbrt,
+ "log1p", MathLog1p, // implemented by third_party/fdlibm
+ "expm1", MathExpm1
));
%SetInlineBuiltinFlag(MathCeil);
%SetInlineBuiltinFlag(MathRandom);
%SetInlineBuiltinFlag(MathSin);
%SetInlineBuiltinFlag(MathCos);
- %SetInlineBuiltinFlag(MathTan);
- %SetInlineBuiltinFlag(TrigonometricInterpolation);
}
SetUpMath();