Skip to content

Commit 930e5cc

Browse files
author
yangguo@chromium.org
committed
Implement Math.expm1 using port from fdlibm.
R=rtoy@chromium.org BUG=v8:3479 LOG=N Review URL: https://codereview.chromium.org/465353002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23238 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent 6313474 commit 930e5cc

7 files changed

Lines changed: 269 additions & 48 deletions

File tree

src/math.js

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -327,26 +327,6 @@ function CubeRoot(x) {
327327
return NEWTON_ITERATION_CBRT(x, approx);
328328
}
329329

330-
// ES6 draft 09-27-13, section 20.2.2.14.
331-
// Use Taylor series to approximate.
332-
// exp(x) - 1 at 0 == -1 + exp(0) + exp'(0)*x/1! + exp''(0)*x^2/2! + ...
333-
// == x/1! + x^2/2! + x^3/3! + ...
334-
// The closer x is to 0, the fewer terms are required.
335-
function MathExpm1(x) {
336-
if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
337-
var xabs = MathAbs(x);
338-
if (xabs < 2E-7) {
339-
return x * (1 + x * (1/2));
340-
} else if (xabs < 6E-5) {
341-
return x * (1 + x * (1/2 + x * (1/6)));
342-
} else if (xabs < 2E-2) {
343-
return x * (1 + x * (1/2 + x * (1/6 +
344-
x * (1/24 + x * (1/120 + x * (1/720))))));
345-
} else { // Use regular exp if not close enough to 0.
346-
return MathExp(x) - 1;
347-
}
348-
}
349-
350330
// -------------------------------------------------------------------
351331

352332
function SetUpMath() {
@@ -408,8 +388,8 @@ function SetUpMath() {
408388
"fround", MathFroundJS,
409389
"clz32", MathClz32,
410390
"cbrt", MathCbrt,
411-
"log1p", MathLog1p, // implemented by third_party/fdlibm
412-
"expm1", MathExpm1
391+
"log1p", MathLog1p, // implemented by third_party/fdlibm
392+
"expm1", MathExpm1 // implemented by third_party/fdlibm
413393
));
414394

415395
%SetInlineBuiltinFlag(MathCeil);

test/mjsunit/es6/math-expm1.js

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@ assertTrue(isNaN(Math.expm1(NaN)));
88
assertTrue(isNaN(Math.expm1(function() {})));
99
assertTrue(isNaN(Math.expm1({ toString: function() { return NaN; } })));
1010
assertTrue(isNaN(Math.expm1({ valueOf: function() { return "abc"; } })));
11-
assertEquals("Infinity", String(1/Math.expm1(0)));
12-
assertEquals("-Infinity", String(1/Math.expm1(-0)));
13-
assertEquals("Infinity", String(Math.expm1(Infinity)));
11+
assertEquals(Infinity, 1/Math.expm1(0));
12+
assertEquals(-Infinity, 1/Math.expm1(-0));
13+
assertEquals(Infinity, Math.expm1(Infinity));
1414
assertEquals(-1, Math.expm1(-Infinity));
1515

16-
for (var x = 0.1; x < 700; x += 0.1) {
16+
17+
// Sanity check:
18+
// Math.expm1(x) stays reasonably close to Math.exp(x) - 1 for large values.
19+
for (var x = 1; x < 700; x += 0.25) {
1720
var expected = Math.exp(x) - 1;
18-
assertEqualsDelta(expected, Math.expm1(x), expected * 1E-14);
21+
assertEqualsDelta(expected, Math.expm1(x), expected * 1E-15);
1922
expected = Math.exp(-x) - 1;
20-
assertEqualsDelta(expected, Math.expm1(-x), -expected * 1E-14);
23+
assertEqualsDelta(expected, Math.expm1(-x), -expected * 1E-15);
2124
}
2225

23-
// Values close to 0:
26+
// Approximation for values close to 0:
2427
// Use six terms of Taylor expansion at 0 for exp(x) as test expectation:
2528
// exp(x) - 1 == exp(0) + exp(0) * x + x * x / 2 + ... - 1
2629
// == x + x * x / 2 + x * x * x / 6 + ...
@@ -32,7 +35,44 @@ function expm1(x) {
3235
1/362880 + x * (1/3628800))))))))));
3336
}
3437

38+
// Sanity check:
39+
// Math.expm1(x) stays reasonabliy close to the Taylor series for small values.
3540
for (var x = 1E-1; x > 1E-300; x *= 0.8) {
3641
var expected = expm1(x);
37-
assertEqualsDelta(expected, Math.expm1(x), expected * 1E-14);
42+
assertEqualsDelta(expected, Math.expm1(x), expected * 1E-15);
3843
}
44+
45+
46+
// Tests related to the fdlibm implementation.
47+
// Test overflow.
48+
assertEquals(Infinity, Math.expm1(709.8));
49+
// Test largest double value.
50+
assertEquals(Infinity, Math.exp(1.7976931348623157e308));
51+
// Cover various code paths.
52+
assertEquals(-1, Math.expm1(-56 * Math.LN2));
53+
assertEquals(-1, Math.expm1(-50));
54+
// Test most negative double value.
55+
assertEquals(-1, Math.expm1(-1.7976931348623157e308));
56+
// Test argument reduction.
57+
// Cases for 0.5*log(2) < |x| < 1.5*log(2).
58+
assertEquals(Math.E - 1, Math.expm1(1));
59+
assertEquals(1/Math.E - 1, Math.expm1(-1));
60+
// Cases for 1.5*log(2) < |x|.
61+
assertEquals(6.38905609893065, Math.expm1(2));
62+
assertEquals(-0.8646647167633873, Math.expm1(-2));
63+
// Cases where Math.expm1(x) = x.
64+
assertEquals(0, Math.expm1(0));
65+
assertEquals(Math.pow(2,-55), Math.expm1(Math.pow(2,-55)));
66+
// Tests for the case where argument reduction has x in the primary range.
67+
// Test branch for k = 0.
68+
assertEquals(0.18920711500272105, Math.expm1(0.25 * Math.LN2));
69+
// Test branch for k = -1.
70+
assertEquals(-0.5, Math.expm1(-Math.LN2));
71+
// Test branch for k = 1.
72+
assertEquals(1, Math.expm1(Math.LN2));
73+
// Test branch for k <= -2 || k > 56. k = -3.
74+
assertEquals(1.4411518807585582e17, Math.expm1(57 * Math.LN2));
75+
// Test last branch for k < 20, k = 19.
76+
assertEquals(524286.99999999994, Math.expm1(19 * Math.LN2));
77+
// Test the else branch, k = 20.
78+
assertEquals(1048575, Math.expm1(20 * Math.LN2));

third_party/fdlibm/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
1+
Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved.
22

33
Developed at SunSoft, a Sun Microsystems, Inc. business.
44
Permission to use, copy, modify, and distribute this

third_party/fdlibm/fdlibm.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ const double MathConstants::constants[] = {
3434
2.02226624879595063154e-21, // pio2_2t 4
3535
2.02226624871116645580e-21, // pio2_3 5
3636
8.47842766036889956997e-32, // pio2_3t 6
37-
-1.66666666666666324348e-01, // S1 7
37+
-1.66666666666666324348e-01, // S1 7 coefficients for sin
3838
8.33333333332248946124e-03, // 8
3939
-1.98412698298579493134e-04, // 9
4040
2.75573137070700676789e-06, // 10
4141
-2.50507602534068634195e-08, // 11
4242
1.58969099521155010221e-10, // S6 12
43-
4.16666666666666019037e-02, // C1 13
43+
4.16666666666666019037e-02, // C1 13 coefficients for cos
4444
-1.38888888888741095749e-03, // 14
4545
2.48015872894767294178e-05, // 15
4646
-2.75573143513906633035e-07, // 16
4747
2.08757232129817482790e-09, // 17
4848
-1.13596475577881948265e-11, // C6 18
49-
3.33333333333334091986e-01, // T0 19
49+
3.33333333333334091986e-01, // T0 19 coefficients for tan
5050
1.33333333333201242699e-01, // 20
5151
5.39682539762260521377e-02, // 21
5252
2.18694882948595424599e-02, // 22
@@ -65,13 +65,20 @@ const double MathConstants::constants[] = {
6565
1.90821492927058770002e-10, // ln2_lo 35
6666
1.80143985094819840000e+16, // 2^54 36
6767
6.666666666666666666e-01, // 2/3 37
68-
6.666666666666735130e-01, // LP1 38
68+
6.666666666666735130e-01, // LP1 38 coefficients for log1p
6969
3.999999999940941908e-01, // 39
7070
2.857142874366239149e-01, // 40
7171
2.222219843214978396e-01, // 41
7272
1.818357216161805012e-01, // 42
7373
1.531383769920937332e-01, // 43
7474
1.479819860511658591e-01, // LP7 44
75+
7.09782712893383973096e+02, // 45 overflow threshold for expm1
76+
1.44269504088896338700e+00, // 1/ln2 46
77+
-3.33333333333331316428e-02, // Q1 47 coefficients for expm1
78+
1.58730158725481460165e-03, // 48
79+
-7.93650757867487942473e-05, // 49
80+
4.00821782732936239552e-06, // 50
81+
-2.01099218183624371326e-07 // Q5 51
7582
};
7683

7784

third_party/fdlibm/fdlibm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ int rempio2(double x, double* y);
2323

2424
// Constants to be exposed to builtins via Float64Array.
2525
struct MathConstants {
26-
static const double constants[45];
26+
static const double constants[52];
2727
};
2828
}
2929
} // namespace v8::internal

0 commit comments

Comments
 (0)