erf.js (10649B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * 19 * ## Notice 20 * 21 * The following copyright, license, and long comment were part of the original implementation available as part of [FreeBSD]{@link https://svnweb.freebsd.org/base/release/9.3.0/lib/msun/src/s_erf.c}. The implementation follows the original, but has been modified for JavaScript. 22 * 23 * ```text 24 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 25 * 26 * Developed at SunPro, a Sun Microsystems, Inc. business. 27 * Permission to use, copy, modify, and distribute this 28 * software is freely granted, provided that this notice 29 * is preserved. 30 * ``` 31 */ 32 33 'use strict'; 34 35 // MODULES // 36 37 var isnan = require( './../../../../base/assert/is-nan' ); 38 var exp = require( './../../../../base/special/exp' ); 39 var setLowWord = require( '@stdlib/number/float64/base/set-low-word' ); 40 var PINF = require( '@stdlib/constants/float64/pinf' ); 41 var NINF = require( '@stdlib/constants/float64/ninf' ); 42 var polyvalPP = require( './polyval_pp.js' ); 43 var polyvalQQ = require( './polyval_qq.js' ); 44 var polyvalPA = require( './polyval_pa.js' ); 45 var polyvalQA = require( './polyval_qa.js' ); 46 var polyvalRA = require( './polyval_ra.js' ); 47 var polyvalSA = require( './polyval_sa.js' ); 48 var polyvalRB = require( './polyval_rb.js' ); 49 var polyvalSB = require( './polyval_sb.js' ); 50 51 52 // VARIABLES // 53 54 var TINY = 1.0e-300; 55 var VERY_TINY = 2.848094538889218e-306; // 0x00800000, 0x00000000 56 57 // 2**-28 = 1/(1<<28) = 1/268435456 58 var SMALL = 3.725290298461914e-9; 59 60 var ERX = 8.45062911510467529297e-1; // 0x3FEB0AC1, 0x60000000 61 62 var EFX = 1.28379167095512586316e-1; // 0x3FC06EBA, 0x8214DB69 63 var EFX8 = 1.02703333676410069053; // 0x3FF06EBA, 0x8214DB69 64 65 var PPC = 1.28379167095512558561e-1; // 0x3FC06EBA, 0x8214DB68 66 var QQC = 1.0; 67 68 var PAC = -2.36211856075265944077e-3; // 0xBF6359B8, 0xBEF77538 69 var QAC = 1.0; 70 71 var RAC = -9.86494403484714822705e-3; // 0xBF843412, 0x600D6435 72 var SAC = 1.0; 73 74 var RBC = -9.86494292470009928597e-3; // 0xBF843412, 0x39E86F4A 75 var SBC = 1.0; 76 77 78 // MAIN // 79 80 /** 81 * Evaluates the error function. 82 * 83 * ```tex 84 * \operatorname{erf}(x) = \frac{2}{\sqrt{\pi}} \int^{x}_{0} e^{-t^2}\ \mathrm{dt} 85 * ``` 86 * 87 * Note that 88 * 89 * ```tex 90 * \begin{align*} 91 * \operatorname{erfc}(x) &= 1 - \operatorname{erf}(x) \\ 92 * \operatorname{erf}(-x) &= -\operatorname{erf}(x) \\ 93 * \operatorname{erfc}(-x) &= 2 - \operatorname{erfc}(x) 94 * \end{align*} 95 * ``` 96 * 97 * ## Method 98 * 99 * 1. For \\(|x| \in [0, 0.84375)\\), 100 * 101 * ```tex 102 * \operatorname{erf}(x) = x + x \cdot \operatorname{R}(x^2) 103 * ``` 104 * 105 * and 106 * 107 * ```tex 108 * \operatorname{erfc}(x) = \begin{cases} 109 * 1 - \operatorname{erf}(x) & \textrm{if}\ x \in (-.84375,0.25) \\ 110 * 0.5 + ((0.5-x)-x \mathrm{R}) & \textrm{if}\ x \in [0.25,0.84375) 111 * \end{cases} 112 * ``` 113 * 114 * where \\(R = P/Q\\) and where \\(P\\) is an odd polynomial of degree \\(8\\) and \\(Q\\) is an odd polynomial of degree \\(10\\). 115 * 116 * ```tex 117 * \biggl| \mathrm{R} - \frac{\operatorname{erf}(x)-x}{x} \biggr| \leq 2^{-57.90} 118 * ``` 119 * 120 * <!-- <note> --> 121 * 122 * The formula is derived by noting 123 * 124 * ```tex 125 * \operatorname{erf}(x) = \frac{2}{\sqrt{\pi}}\biggl(x - \frac{x^3}{3} + \frac{x^5}{10} - \frac{x^7}{42} + \ldots \biggr) 126 * ``` 127 * 128 * and that 129 * 130 * ```tex 131 * \frac{2}{\sqrt{\pi}} = 1.128379167095512573896158903121545171688 132 * ``` 133 * 134 * is close to unity. The interval is chosen because the fix point of \\(\operatorname{erf}(x)\\) is near \\(0.6174\\) (i.e., \\(\operatorname{erf(x)} = x\\) when \\(x\\) is near \\(0.6174\\)), and, by some experiment, \\(0.84375\\) is chosen to guarantee the error is less than one ulp for \\(\operatorname{erf}(x)\\). 135 * 136 * <!-- </note> --> 137 * 138 * 2. For \\(|x| \in [0.84375,1.25)\\), let \\(s = |x|-1\\), and \\(c = 0.84506291151\\) rounded to single (\\(24\\) bits) 139 * 140 * ```tex 141 * \operatorname{erf}(x) = \operatorname{sign}(x) \cdot \biggl(c + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)}\biggr) 142 * ``` 143 * 144 * and 145 * 146 * ```tex 147 * \operatorname{erfc}(x) = \begin{cases} 148 * (1-c) - \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)} & \textrm{if}\ x > 0 \\ 149 * 1 + \biggl(c + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)}\biggr) & \textrm{if}\ x < 0 150 * \end{cases} 151 * ``` 152 * 153 * where 154 * 155 * ```tex 156 * \biggl|\frac{\mathrm{P1}}{\mathrm{Q1}} - (\operatorname{erf}(|x|)-c)\biggr| \leq 2^{-59.06} 157 * ``` 158 * 159 * <!-- <note> --> 160 * 161 * Here, we use the Taylor series expansion at \\(x = 1\\) 162 * 163 * ```tex 164 * \begin{align*} 165 * \operatorname{erf}(1+s) &= \operatorname{erf}(1) + s\cdot \operatorname{poly}(s) \\ 166 * &= 0.845.. + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)} 167 * \end{align*} 168 * ``` 169 * 170 * using a rational approximation to approximate 171 * 172 * ```tex 173 * \operatorname{erf}(1+s) - (c = (\mathrm{single})0.84506291151) 174 * ``` 175 * 176 * <!-- </note> --> 177 * 178 * Note that, for \\(x \in [0.84375,1.25)\\), \\(|\mathrm{P1}/\mathrm{Q1}| < 0.078\\), where 179 * 180 * - \\(\operatorname{P1}(s)\\) is a degree \\(6\\) polynomial in \\(s\\) 181 * - \\(\operatorname{Q1}(s)\\) is a degree \\(6\\) polynomial in \\(s\\) 182 * 183 * 3. For \\(x \in [1.25,1/0.35)\\), 184 * 185 * ```tex 186 * \begin{align*} 187 * \operatorname{erfc}(x) &= \frac{1}{x}e^{-x^2-0.5625+(\mathrm{R1}/\mathrm{S1})} \\ 188 * \operatorname{erf}(x) &= 1 - \operatorname{erfc}(x) 189 * \end{align*} 190 * ``` 191 * 192 * where 193 * 194 * - \\(\operatorname{R1}(z)\\) is a degree \\(7\\) polynomial in \\(z\\), where \\(z = 1/x^2\\) 195 * - \\(\operatorname{S1}(z)\\) is a degree \\(8\\) polynomial in \\(z\\) 196 * 197 * 4. For \\(x \in [1/0.35,28)\\), 198 * 199 * ```tex 200 * \operatorname{erfc}(x) = \begin{cases} 201 * \frac{1}{x} e^{-x^2-0.5625+(\mathrm{R2}/\mathrm{S2})} & \textrm{if}\ x > 0 \\ 202 * 2.0 - \frac{1}{x} e^{-x^2-0.5625+(\mathrm{R2}/\mathrm{S2})} & \textrm{if}\ -6 < x < 0 \\ 203 * 2.0 - \mathrm{tiny} & \textrm{if}\ x \leq -6 204 * \end{cases} 205 * ``` 206 * 207 * and 208 * 209 * ```tex 210 * \operatorname{erf}(x) = \begin{cases} 211 * \operatorname{sign}(x) \cdot (1.0 - \operatorname{erfc}(x)) & \textrm{if}\ x < 6 \\ 212 * \operatorname{sign}(x) \cdot (1.0 - \mathrm{tiny}) & \textrm{otherwise} 213 * \end{cases} 214 * ``` 215 * 216 * where 217 * 218 * - \\(\operatorname{R2}(z)\\) is a degree \\(6\\) polynomial in \\(z\\), where \\(z = 1/x^2\\) 219 * - \\(\operatorname{S2}(z)\\) is a degree \\(7\\) polynomial in \\(z\\) 220 * 221 * 5. For \\(x \in [28, \infty)\\), 222 * 223 * ```tex 224 * \begin{align*} 225 * \operatorname{erf}(x) &= \operatorname{sign}(x) \cdot (1 - \mathrm{tiny}) & \textrm{(raise inexact)} 226 * \end{align*} 227 * ``` 228 * 229 * and 230 * 231 * ```tex 232 * \operatorname{erfc}(x) = \begin{cases} 233 * \mathrm{tiny} \cdot \mathrm{tiny} & \textrm{if}\ x > 0\ \textrm{(raise underflow)} \\ 234 * 2 - \mathrm{tiny} & \textrm{if}\ x < 0 235 * \end{cases} 236 * ``` 237 * 238 * ## Special Cases 239 * 240 * ```tex 241 * \begin{align*} 242 * \operatorname{erf}(0) &= 0 \\ 243 * \operatorname{erf}(-0) &= -0 \\ 244 * \operatorname{erf}(\infty) &= 1 \\ 245 * \operatorname{erf}(-\infty) &= -1 \\ 246 * \operatorname{erfc}(0) &= 1 \\ 247 * \operatorname{erfc}(\infty) &= 0 \\ 248 * \operatorname{erfc}(-\infty) &= 2 \\ 249 * \operatorname{erf}(\mathrm{NaN}) &= \mathrm{NaN} \\ 250 * \operatorname{erfc}(\mathrm{NaN}) &= \mathrm{NaN} 251 * \end{align*} 252 * ``` 253 * 254 * 255 * ## Notes 256 * 257 * - To compute \\(\exp(-x^2-0.5625+(\mathrm{R}/\mathrm{S}))\\), let \\(s\\) be a single precision number and \\(s := x\\); then 258 * 259 * ```tex 260 * -x^2 = -s^2 + (s-x)(s+x) 261 * ``` 262 * 263 * and 264 * 265 * ```tex 266 * e^{-x^2-0.5626+(\mathrm{R}/\mathrm{S})} = e^{-s^2-0.5625} e^{(s-x)(s+x)+(\mathrm{R}/\mathrm{S})} 267 * ``` 268 * 269 * - `#4` and `#5` make use of the asymptotic series 270 * 271 * ```tex 272 * \operatorname{erfc}(x) \approx \frac{e^{-x^2}}{x\sqrt{\pi}} (1 + \operatorname{poly}(1/x^2)) 273 * ``` 274 * 275 * We use a rational approximation to approximate 276 * 277 * ```tex 278 * g(s) = f(1/x^2) = \ln(\operatorname{erfc}(x) \cdot x) - x^2 + 0.5625 279 * ``` 280 * 281 * - The error bound for \\(\mathrm{R1}/\mathrm{S1}\\) is 282 * 283 * ```tex 284 * |\mathrm{R1}/\mathrm{S1} - f(x)| < 2^{-62.57} 285 * ``` 286 * 287 * and for \\(\mathrm{R2}/\mathrm{S2}\\) is 288 * 289 * ```tex 290 * |\mathrm{R2}/\mathrm{S2} - f(x)| < 2^{-61.52} 291 * ``` 292 * 293 * @param {number} x - input value 294 * @returns {number} function value 295 * 296 * @example 297 * var y = erf( 2.0 ); 298 * // returns ~0.9953 299 * 300 * @example 301 * var y = erf( -1.0 ); 302 * // returns ~-0.8427 303 * 304 * @example 305 * var y = erf( -0.0 ); 306 * // returns -0.0 307 * 308 * @example 309 * var y = erf( NaN ); 310 * // returns NaN 311 */ 312 function erf( x ) { 313 var sign; 314 var ax; 315 var z; 316 var r; 317 var s; 318 var y; 319 var p; 320 var q; 321 322 // Special case: NaN 323 if ( isnan( x ) ) { 324 return NaN; 325 } 326 // Special case: +infinity 327 if ( x === PINF ) { 328 return 1.0; 329 } 330 // Special case: -infinity 331 if ( x === NINF ) { 332 return -1.0; 333 } 334 // Special case: +-0 335 if ( x === 0.0 ) { 336 return x; 337 } 338 if ( x < 0.0 ) { 339 sign = true; 340 ax = -x; 341 } else { 342 sign = false; 343 ax = x; 344 } 345 // |x| < 0.84375 346 if ( ax < 0.84375 ) { 347 if ( ax < SMALL ) { 348 if ( ax < VERY_TINY ) { 349 // Avoid underflow: 350 return 0.125 * ( (8.0*x) + (EFX8*x) ); 351 } 352 return x + (EFX*x); 353 } 354 z = x * x; 355 r = PPC + ( z*polyvalPP( z ) ); 356 s = QQC + ( z*polyvalQQ( z ) ); 357 y = r / s; 358 return x + (x*y); 359 } 360 // 0.84375 <= |x| < 1.25 361 if ( ax < 1.25 ) { 362 s = ax - 1.0; 363 p = PAC + ( s*polyvalPA( s ) ); 364 q = QAC + ( s*polyvalQA( s ) ); 365 if ( sign ) { 366 return -ERX - (p/q); 367 } 368 return ERX + (p/q); 369 } 370 // +inf > |x| >= 6 371 if ( ax >= 6.0 ) { 372 if ( sign ) { 373 return TINY - 1.0; // raise inexact 374 } 375 return 1.0 - TINY; // raise inexact 376 } 377 s = 1.0 / (ax*ax); 378 379 // |x| < 1/0.35 ~ 2.857143 380 if ( ax < 2.857142857142857 ) { 381 r = RAC + ( s*polyvalRA( s ) ); 382 s = SAC + ( s*polyvalSA( s ) ); 383 } 384 // |x| >= 1/0.35 ~ 2.857143 385 else { 386 r = RBC + ( s*polyvalRB( s ) ); 387 s = SBC + ( s*polyvalSB( s ) ); 388 } 389 z = setLowWord( ax, 0 ); // pseudo-single (20-bit) precision x 390 r = exp( -(z*z) - 0.5625 ) * exp( ( (z-ax) * (z+ax) ) + (r/s) ); 391 if ( sign ) { 392 return (r/ax) - 1.0; 393 } 394 return 1.0 - (r/ax); 395 } 396 397 398 // EXPORTS // 399 400 module.exports = erf;