Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1 | // The following is adapted from fdlibm (http://www.netlib.org/fdlibm), |
| 2 | // |
| 3 | // ==================================================== |
| 4 | // Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved. |
| 5 | // |
| 6 | // Developed at SunSoft, a Sun Microsystems, Inc. business. |
| 7 | // Permission to use, copy, modify, and distribute this |
| 8 | // software is freely granted, provided that this notice |
| 9 | // is preserved. |
| 10 | // ==================================================== |
| 11 | // |
| 12 | // The original source code covered by the above license above has been |
| 13 | // modified significantly by Google Inc. |
| 14 | // Copyright 2014 the V8 project authors. All rights reserved. |
| 15 | // |
| 16 | // The following is a straightforward translation of fdlibm routines |
| 17 | // by Raymond Toy (rtoy@google.com). |
| 18 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 19 | (function(global, utils) { |
| 20 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 21 | "use strict"; |
| 22 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 23 | %CheckIsBootstrapping(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 24 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 25 | // ------------------------------------------------------------------- |
| 26 | // Imports |
| 27 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 28 | var GlobalMath = global.Math; |
| 29 | var MathAbs; |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 30 | var MathExpm1; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 31 | |
| 32 | utils.Import(function(from) { |
| 33 | MathAbs = from.MathAbs; |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 34 | MathExpm1 = from.MathExpm1; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 35 | }); |
| 36 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 37 | // ES6 draft 09-27-13, section 20.2.2.30. |
| 38 | // Math.sinh |
| 39 | // Method : |
| 40 | // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 |
| 41 | // 1. Replace x by |x| (sinh(-x) = -sinh(x)). |
| 42 | // 2. |
| 43 | // E + E/(E+1) |
| 44 | // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) |
| 45 | // 2 |
| 46 | // |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 47 | // 22 <= x <= lnovft : sinh(x) := exp(x)/2 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 48 | // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) |
| 49 | // ln2ovft < x : sinh(x) := x*shuge (overflow) |
| 50 | // |
| 51 | // Special cases: |
| 52 | // sinh(x) is |x| if x is +Infinity, -Infinity, or NaN. |
| 53 | // only sinh(0)=0 is exact for finite x. |
| 54 | // |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 55 | define KSINH_OVERFLOW = 710.4758600739439; |
| 56 | define TWO_M28 = 3.725290298461914e-9; // 2^-28, empty lower half |
| 57 | define LOG_MAXD = 709.7822265625; // 0x40862e42 00000000, empty lower half |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 58 | |
| 59 | function MathSinh(x) { |
| 60 | x = x * 1; // Convert to number. |
| 61 | var h = (x < 0) ? -0.5 : 0.5; |
| 62 | // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1)) |
| 63 | var ax = MathAbs(x); |
| 64 | if (ax < 22) { |
| 65 | // For |x| < 2^-28, sinh(x) = x |
| 66 | if (ax < TWO_M28) return x; |
| 67 | var t = MathExpm1(ax); |
| 68 | if (ax < 1) return h * (2 * t - t * t / (t + 1)); |
| 69 | return h * (t + t / (t + 1)); |
| 70 | } |
| 71 | // |x| in [22, log(maxdouble)], return 0.5 * exp(|x|) |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 72 | if (ax < LOG_MAXD) return h * %math_exp(ax); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 73 | // |x| in [log(maxdouble), overflowthreshold] |
| 74 | // overflowthreshold = 710.4758600739426 |
| 75 | if (ax <= KSINH_OVERFLOW) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 76 | var w = %math_exp(0.5 * ax); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 77 | var t = h * w; |
| 78 | return t * w; |
| 79 | } |
| 80 | // |x| > overflowthreshold or is NaN. |
| 81 | // Return Infinity of the appropriate sign or NaN. |
| 82 | return x * INFINITY; |
| 83 | } |
| 84 | |
| 85 | |
| 86 | // ES6 draft 09-27-13, section 20.2.2.12. |
| 87 | // Math.cosh |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 88 | // Method : |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 89 | // mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 90 | // 1. Replace x by |x| (cosh(x) = cosh(-x)). |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 91 | // 2. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 92 | // [ exp(x) - 1 ]^2 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 93 | // 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- |
| 94 | // 2*exp(x) |
| 95 | // |
| 96 | // exp(x) + 1/exp(x) |
| 97 | // ln2/2 <= x <= 22 : cosh(x) := ------------------- |
| 98 | // 2 |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 99 | // 22 <= x <= lnovft : cosh(x) := exp(x)/2 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 100 | // lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) |
| 101 | // ln2ovft < x : cosh(x) := huge*huge (overflow) |
| 102 | // |
| 103 | // Special cases: |
| 104 | // cosh(x) is |x| if x is +INF, -INF, or NaN. |
| 105 | // only cosh(0)=1 is exact for finite x. |
| 106 | // |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 107 | define KCOSH_OVERFLOW = 710.4758600739439; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 108 | |
| 109 | function MathCosh(x) { |
| 110 | x = x * 1; // Convert to number. |
| 111 | var ix = %_DoubleHi(x) & 0x7fffffff; |
| 112 | // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|)) |
| 113 | if (ix < 0x3fd62e43) { |
| 114 | var t = MathExpm1(MathAbs(x)); |
| 115 | var w = 1 + t; |
| 116 | // For |x| < 2^-55, cosh(x) = 1 |
| 117 | if (ix < 0x3c800000) return w; |
| 118 | return 1 + (t * t) / (w + w); |
| 119 | } |
| 120 | // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2 |
| 121 | if (ix < 0x40360000) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 122 | var t = %math_exp(MathAbs(x)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 123 | return 0.5 * t + 0.5 / t; |
| 124 | } |
| 125 | // |x| in [22, log(maxdouble)], return half*exp(|x|) |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 126 | if (ix < 0x40862e42) return 0.5 * %math_exp(MathAbs(x)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 127 | // |x| in [log(maxdouble), overflowthreshold] |
| 128 | if (MathAbs(x) <= KCOSH_OVERFLOW) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 129 | var w = %math_exp(0.5 * MathAbs(x)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 130 | var t = 0.5 * w; |
| 131 | return t * w; |
| 132 | } |
| 133 | if (NUMBER_IS_NAN(x)) return x; |
| 134 | // |x| > overflowthreshold. |
| 135 | return INFINITY; |
| 136 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 137 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 138 | // ES6 draft 09-27-13, section 20.2.2.33. |
| 139 | // Math.tanh(x) |
| 140 | // Method : |
| 141 | // x -x |
| 142 | // e - e |
| 143 | // 0. tanh(x) is defined to be ----------- |
| 144 | // x -x |
| 145 | // e + e |
| 146 | // 1. reduce x to non-negative by tanh(-x) = -tanh(x). |
| 147 | // 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x) |
| 148 | // -t |
| 149 | // 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) |
| 150 | // t + 2 |
| 151 | // 2 |
| 152 | // 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t = expm1(2x) |
| 153 | // t + 2 |
| 154 | // 22.0 < x <= INF : tanh(x) := 1. |
| 155 | // |
| 156 | // Special cases: |
| 157 | // tanh(NaN) is NaN; |
| 158 | // only tanh(0) = 0 is exact for finite argument. |
| 159 | // |
| 160 | |
| 161 | define TWO_M55 = 2.77555756156289135105e-17; // 2^-55, empty lower half |
| 162 | |
| 163 | function MathTanh(x) { |
| 164 | x = x * 1; // Convert to number. |
| 165 | // x is Infinity or NaN |
| 166 | if (!NUMBER_IS_FINITE(x)) { |
| 167 | if (x > 0) return 1; |
| 168 | if (x < 0) return -1; |
| 169 | return x; |
| 170 | } |
| 171 | |
| 172 | var ax = MathAbs(x); |
| 173 | var z; |
| 174 | // |x| < 22 |
| 175 | if (ax < 22) { |
| 176 | if (ax < TWO_M55) { |
| 177 | // |x| < 2^-55, tanh(small) = small. |
| 178 | return x; |
| 179 | } |
| 180 | if (ax >= 1) { |
| 181 | // |x| >= 1 |
| 182 | var t = MathExpm1(2 * ax); |
| 183 | z = 1 - 2 / (t + 2); |
| 184 | } else { |
| 185 | var t = MathExpm1(-2 * ax); |
| 186 | z = -t / (t + 2); |
| 187 | } |
| 188 | } else { |
| 189 | // |x| > 22, return +/- 1 |
| 190 | z = 1; |
| 191 | } |
| 192 | return (x >= 0) ? z : -z; |
| 193 | } |
| 194 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 195 | //------------------------------------------------------------------- |
| 196 | |
| 197 | utils.InstallFunctions(GlobalMath, DONT_ENUM, [ |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 198 | "sinh", MathSinh, |
| 199 | "cosh", MathCosh, |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 200 | "tanh", MathTanh |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 201 | ]); |
| 202 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 203 | }) |