Port fdlibm implementation for Math.sinh.

R=rtoy@chromium.org
BUG=v8:3493
LOG=N

Review URL: https://codereview.chromium.org/488003005

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23512 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-08-29 09:32:51 +00:00
parent 9091e87d8f
commit 8938126d1b
6 changed files with 94 additions and 20 deletions

View File

@ -186,14 +186,6 @@ function MathTrunc(x) {
return x;
}
// 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);
@ -376,7 +368,7 @@ function SetUpMath() {
"imul", MathImul,
"sign", MathSign,
"trunc", MathTrunc,
"sinh", MathSinh,
"sinh", MathSinh, // implemented by third_party/fdlibm
"cosh", MathCosh,
"tanh", MathTanh,
"asinh", MathAsinh,

View File

@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(3468): we rely on a precise Math.exp.
// Flags: --no-fast-math
[Math.sinh, Math.cosh, Math.tanh, Math.asinh, Math.acosh, Math.atanh].
forEach(function(fun) {
assertTrue(isNaN(fun(NaN)));
@ -66,14 +69,14 @@ function test_id(fun, rev, value) {
});
assertEquals("Infinity", String(Math.cosh(-Infinity)));
assertEquals("Infinity", String(Math.cosh(Infinity)));
assertEquals("Infinity", String(Math.cosh("-Infinity")));
assertEquals("Infinity", String(Math.cosh("Infinity")));
assertEquals(Infinity, Math.cosh(-Infinity));
assertEquals(Infinity, Math.cosh(Infinity));
assertEquals(Infinity, Math.cosh("-Infinity"));
assertEquals(Infinity, Math.cosh("Infinity"));
assertEquals("-Infinity", String(Math.atanh(-1)));
assertEquals("Infinity", String(Math.atanh(1)));
assertEquals(-Infinity, Math.atanh(-1));
assertEquals(Infinity, Math.atanh(1));
// Math.atanh(x) is NaN for |x| > 1 and NaN
[1.000000000001, Math.PI, 10000000, 2, Infinity, NaN].forEach(function(x) {
@ -82,6 +85,8 @@ assertEquals("Infinity", String(Math.atanh(1)));
});
assertEquals(0, Math.sinh(0));
assertEquals(-Infinity, 1/Math.sinh(-0));
assertEquals(1, Math.tanh(Infinity));
assertEquals(-1, Math.tanh(-Infinity));
assertEquals(1, Math.cosh(0));
@ -97,9 +102,7 @@ assertEquals("Infinity", String(Math.acosh(Infinity)));
// Some random samples.
assertEqualsDelta(0.5210953054937, Math.sinh(0.5), 1E-12);
assertEqualsDelta(74.203210577788, Math.sinh(5), 1E-12);
assertEqualsDelta(-0.5210953054937, Math.sinh(-0.5), 1E-12);
assertEqualsDelta(-74.203210577788, Math.sinh(-5), 1E-12);
assertEqualsDelta(1.1276259652063, Math.cosh(0.5), 1E-12);
@ -134,3 +137,32 @@ assertEqualsDelta(-0.1003353477311, Math.atanh(-0.1), 1E-12);
[1-(1E-16), 0, 1E-10, 1E-50].forEach(function(x) {
assertEqualsDelta(Math.atanh(x), -Math.atanh(-x), 1E-12);
});
// Implementation-specific tests for sinh.
// Case |x| < 2^-28
assertEquals(Math.pow(2, -29), Math.sinh(Math.pow(2, -29)));
assertEquals(-Math.pow(2, -29), Math.sinh(-Math.pow(2, -29)));
// Case |x| < 1
assertEquals(0.5210953054937474, Math.sinh(0.5));
assertEquals(-0.5210953054937474, Math.sinh(-0.5));
// sinh(10*log(2)) = 1048575/2048, case |x| < 22
assertEquals(1048575/2048, Math.sinh(10*Math.LN2));
assertEquals(-1048575/2048, Math.sinh(-10*Math.LN2));
// Case |x| < 22
assertEquals(11013.232874703393, Math.sinh(10));
assertEquals(-11013.232874703393, Math.sinh(-10));
// Case |x| in [22, log(maxdouble)]
assertEquals(2.1474836479999983e9, Math.sinh(32*Math.LN2));
assertEquals(-2.1474836479999983e9, Math.sinh(-32*Math.LN2));
// Case |x| in [22, log(maxdouble)]
assertEquals(1.3440585709080678e43, Math.sinh(100));
assertEquals(-1.3440585709080678e43, Math.sinh(-100));
// No overflow, case |x| in [log(maxdouble), threshold]
assertEquals(1.7976931348621744e308, Math.sinh(710.4758600739439));
assertEquals(-1.7976931348621744e308, Math.sinh(-710.4758600739439));
// Overflow, case |x| > threshold
assertEquals(Infinity, Math.sinh(710.475860073944));
assertEquals(-Infinity, Math.sinh(-710.475860073944));
assertEquals(Infinity, Math.sinh(1000));
assertEquals(-Infinity, Math.sinh(-1000));

View File

@ -78,7 +78,8 @@ const double MathConstants::constants[] = {
1.58730158725481460165e-03, // 48
-7.93650757867487942473e-05, // 49
4.00821782732936239552e-06, // 50
-2.01099218183624371326e-07 // Q5 51
-2.01099218183624371326e-07, // Q5 51
710.4758600739439 // 52 overflow threshold for sinh
};

View File

@ -23,7 +23,7 @@ int rempio2(double x, double* y);
// Constants to be exposed to builtins via Float64Array.
struct MathConstants {
static const double constants[52];
static const double constants[53];
};
}
} // namespace v8::internal

View File

@ -710,3 +710,52 @@ function MathExpm1(x) {
}
return y;
}
// ES6 draft 09-27-13, section 20.2.2.30.
// Math.sinh
// Method :
// mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
// 1. Replace x by |x| (sinh(-x) = -sinh(x)).
// 2.
// E + E/(E+1)
// 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
// 2
//
// 22 <= x <= lnovft : sinh(x) := exp(x)/2
// lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
// ln2ovft < x : sinh(x) := x*shuge (overflow)
//
// Special cases:
// sinh(x) is |x| if x is +Infinity, -Infinity, or NaN.
// only sinh(0)=0 is exact for finite x.
//
const KSINH_OVERFLOW = kMath[52];
const TWO_M28 = 3.725290298461914e-9; // 2^-28, empty lower half
const LOG_MAXD = 709.7822265625; // 0x40862e42 00000000, empty lower half
function MathSinh(x) {
x = x * 1; // Convert to number.
var h = (x < 0) ? -0.5 : 0.5;
// |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1))
var ax = MathAbs(x);
if (ax < 22) {
// For |x| < 2^-28, sinh(x) = x
if (ax < TWO_M28) return x;
var t = MathExpm1(ax);
if (ax < 1) return h * (2 * t - t * t / (t + 1));
return h * (t + t / (t + 1));
}
// |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
if (ax < LOG_MAXD) return h * MathExp(ax);
// |x| in [log(maxdouble), overflowthreshold]
// overflowthreshold = 710.4758600739426
if (ax <= KSINH_OVERFLOW) {
var w = MathExp(0.5 * ax);
var t = h * w;
return t * w;
}
// |x| > overflowthreshold or is NaN.
// Return Infinity of the appropriate sign or NaN.
return x * INFINITY;
}

View File

@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 431
EXPECTED_FUZZABLE_COUNT = 332
EXPECTED_CCTEST_COUNT = 7
EXPECTED_UNKNOWN_COUNT = 17
EXPECTED_BUILTINS_COUNT = 808
EXPECTED_BUILTINS_COUNT = 807
# Don't call these at all.