erfc.js (10704B)
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 56 // 2**-56 = 1/(2**56) = 1/72057594037927940 57 var SMALL = 1.3877787807814457e-17; 58 59 var ERX = 8.45062911510467529297e-1; // 0x3FEB0AC1, 0x60000000 60 61 var PPC = 1.28379167095512558561e-1; // 0x3FC06EBA, 0x8214DB68 62 var QQC = 1.0; 63 64 var PAC = -2.36211856075265944077e-3; // 0xBF6359B8, 0xBEF77538 65 var QAC = 1.0; 66 67 var RAC = -9.86494403484714822705e-3; // 0xBF843412, 0x600D6435 68 var SAC = 1.0; 69 70 var RBC = -9.86494292470009928597e-3; // 0xBF843412, 0x39E86F4A 71 var SBC = 1.0; 72 73 74 // MAIN // 75 76 /** 77 * Evaluates the complementary error function. 78 * 79 * ```tex 80 * \operatorname{erf}(x) = \frac{2}{\sqrt{\pi}} \int^{x}_{0} e^{-t^2}\ \mathrm{dt} 81 * ``` 82 * 83 * Note that 84 * 85 * ```tex 86 * \begin{align*} 87 * \operatorname{erfc}(x) &= 1 - \operatorname{erf}(x) \\ 88 * \operatorname{erf}(-x) &= -\operatorname{erf}(x) \\ 89 * \operatorname{erfc}(-x) &= 2 - \operatorname{erfc}(x) 90 * \end{align*} 91 * ``` 92 * 93 * ## Method 94 * 95 * 1. For \\(|x| \in [0, 0.84375)\\), 96 * 97 * ```tex 98 * \operatorname{erf}(x) = x + x \cdot \operatorname{R}(x^2) 99 * ``` 100 * 101 * and 102 * 103 * ```tex 104 * \operatorname{erfc}(x) = \begin{cases} 105 * 1 - \operatorname{erf}(x) & \textrm{if}\ x \in (-.84375,0.25) \\ 106 * 0.5 + ((0.5-x)-x \mathrm{R}) & \textrm{if}\ x \in [0.25,0.84375) 107 * \end{cases} 108 * ``` 109 * 110 * where \\(R = P/Q\\) and where \\(P\\) is an odd polynomial of degree \\(8\\) and \\(Q\\) is an odd polynomial of degree \\(10\\). 111 * 112 * ```tex 113 * \biggl| \mathrm{R} - \frac{\operatorname{erf}(x)-x}{x} \biggr| \leq 2^{-57.90} 114 * ``` 115 * 116 * <!-- <note> --> 117 * 118 * The formula is derived by noting 119 * 120 * ```tex 121 * \operatorname{erf}(x) = \frac{2}{\sqrt{\pi}}\biggl(x - \frac{x^3}{3} + \frac{x^5}{10} - \frac{x^7}{42} + \ldots \biggr) 122 * ``` 123 * 124 * and that 125 * 126 * ```tex 127 * \frac{2}{\sqrt{\pi}} = 1.128379167095512573896158903121545171688 128 * ``` 129 * 130 * 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)\\). 131 * 132 * <!-- </note> --> 133 * 134 * 2. For \\(|x| \in [0.84375,1.25)\\), let \\(s = |x|-1\\), and \\(c = 0.84506291151\\) rounded to single (\\(24\\) bits) 135 * 136 * ```tex 137 * \operatorname{erf}(x) = \operatorname{sign}(x) \cdot \biggl(c + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)}\biggr) 138 * ``` 139 * 140 * and 141 * 142 * ```tex 143 * \operatorname{erfc}(x) = \begin{cases} 144 * (1-c) - \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)} & \textrm{if}\ x > 0 \\ 145 * 1 + \biggl(c + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)}\biggr) & \textrm{if}\ x < 0 146 * \end{cases} 147 * ``` 148 * 149 * where 150 * 151 * ```tex 152 * \biggl|\frac{\mathrm{P1}}{\mathrm{Q1}} - (\operatorname{erf}(|x|)-c)\biggr| \leq 2^{-59.06} 153 * ``` 154 * 155 * <!-- <note> --> 156 * 157 * Here, we use the Taylor series expansion at \\(x = 1\\) 158 * 159 * ```tex 160 * \begin{align*} 161 * \operatorname{erf}(1+s) &= \operatorname{erf}(1) + s\cdot \operatorname{poly}(s) \\ 162 * &= 0.845.. + \frac{\operatorname{P1}(s)}{\operatorname{Q1}(s)} 163 * \end{align*} 164 * ``` 165 * 166 * using a rational approximation to approximate 167 * 168 * ```tex 169 * \operatorname{erf}(1+s) - (c = (\mathrm{single})0.84506291151) 170 * ``` 171 * 172 * <!-- </note> --> 173 * 174 * Note that, for \\(x \in [0.84375,1.25)\\), \\(|\mathrm{P1}/\mathrm{Q1}| < 0.078\\), where 175 * 176 * - \\(\operatorname{P1}(s)\\) is a degree \\(6\\) polynomial in \\(s\\) 177 * - \\(\operatorname{Q1}(s)\\) is a degree \\(6\\) polynomial in \\(s\\) 178 * 179 * 3. For \\(x \in [1.25,1/0.35)\\), 180 * 181 * ```tex 182 * \begin{align*} 183 * \operatorname{erfc}(x) &= \frac{1}{x}e^{-x^2-0.5625+(\mathrm{R1}/\mathrm{S1})} \\ 184 * \operatorname{erf}(x) &= 1 - \operatorname{erfc}(x) 185 * \end{align*} 186 * ``` 187 * 188 * where 189 * 190 * - \\(\operatorname{R1}(z)\\) is a degree \\(7\\) polynomial in \\(z\\), where \\(z = 1/x^2\\) 191 * - \\(\operatorname{S1}(z)\\) is a degree \\(8\\) polynomial in \\(z\\) 192 * 193 * 4. For \\(x \in [1/0.35,28)\\), 194 * 195 * ```tex 196 * \operatorname{erfc}(x) = \begin{cases} 197 * \frac{1}{x} e^{-x^2-0.5625+(\mathrm{R2}/\mathrm{S2})} & \textrm{if}\ x > 0 \\ 198 * 2.0 - \frac{1}{x} e^{-x^2-0.5625+(\mathrm{R2}/\mathrm{S2})} & \textrm{if}\ -6 < x < 0 \\ 199 * 2.0 - \mathrm{tiny} & \textrm{if}\ x \leq -6 200 * \end{cases} 201 * ``` 202 * 203 * and 204 * 205 * ```tex 206 * \operatorname{erf}(x) = \begin{cases} 207 * \operatorname{sign}(x) \cdot (1.0 - \operatorname{erfc}(x)) & \textrm{if}\ x < 6 \\ 208 * \operatorname{sign}(x) \cdot (1.0 - \mathrm{tiny}) & \textrm{otherwise} 209 * \end{cases} 210 * ``` 211 * 212 * where 213 * 214 * - \\(\operatorname{R2}(z)\\) is a degree \\(6\\) polynomial in \\(z\\), where \\(z = 1/x^2\\) 215 * - \\(\operatorname{S2}(z)\\) is a degree \\(7\\) polynomial in \\(z\\) 216 * 217 * 5. For \\(x \in [28, \infty)\\), 218 * 219 * ```tex 220 * \begin{align*} 221 * \operatorname{erf}(x) &= \operatorname{sign}(x) \cdot (1 - \mathrm{tiny}) & \textrm{(raise inexact)} 222 * \end{align*} 223 * ``` 224 * 225 * and 226 * 227 * ```tex 228 * \operatorname{erfc}(x) = \begin{cases} 229 * \mathrm{tiny} \cdot \mathrm{tiny} & \textrm{if}\ x > 0\ \textrm{(raise underflow)} \\ 230 * 2 - \mathrm{tiny} & \textrm{if}\ x < 0 231 * \end{cases} 232 * ``` 233 * 234 * 235 * ## Special Cases 236 * 237 * ```tex 238 * \begin{align*} 239 * \operatorname{erf}(0) &= 0 \\ 240 * \operatorname{erf}(-0) &= -0 \\ 241 * \operatorname{erf}(\infty) &= 1 \\ 242 * \operatorname{erf}(-\infty) &= -1 \\ 243 * \operatorname{erfc}(0) &= 1 \\ 244 * \operatorname{erfc}(\infty) &= 0 \\ 245 * \operatorname{erfc}(-\infty) &= 2 \\ 246 * \operatorname{erf}(\mathrm{NaN}) &= \mathrm{NaN} \\ 247 * \operatorname{erfc}(\mathrm{NaN}) &= \mathrm{NaN} 248 * \end{align*} 249 * ``` 250 * 251 * 252 * ## Notes 253 * 254 * - To compute \\(\exp(-x^2-0.5625+(\mathrm{R}/\mathrm{S}))\\), let \\(s\\) be a single precision number and \\(s := x\\); then 255 * 256 * ```tex 257 * -x^2 = -s^2 + (s-x)(s+x) 258 * ``` 259 * 260 * and 261 * 262 * ```tex 263 * e^{-x^2-0.5626+(\mathrm{R}/\mathrm{S})} = e^{-s^2-0.5625} e^{(s-x)(s+x)+(\mathrm{R}/\mathrm{S})} 264 * ``` 265 * 266 * - `#4` and `#5` make use of the asymptotic series 267 * 268 * ```tex 269 * \operatorname{erfc}(x) \approx \frac{e^{-x^2}}{x\sqrt{\pi}} (1 + \operatorname{poly}(1/x^2)) 270 * ``` 271 * 272 * We use a rational approximation to approximate 273 * 274 * ```tex 275 * g(s) = f(1/x^2) = \ln(\operatorname{erfc}(x) \cdot x) - x^2 + 0.5625 276 * ``` 277 * 278 * - The error bound for \\(\mathrm{R1}/\mathrm{S1}\\) is 279 * 280 * ```tex 281 * |\mathrm{R1}/\mathrm{S1} - f(x)| < 2^{-62.57} 282 * ``` 283 * 284 * and for \\(\mathrm{R2}/\mathrm{S2}\\) is 285 * 286 * ```tex 287 * |\mathrm{R2}/\mathrm{S2} - f(x)| < 2^{-61.52} 288 * ``` 289 * 290 * @param {number} x - input value 291 * @returns {number} function value 292 * 293 * @example 294 * var y = erfc( 2.0 ); 295 * // returns ~0.0047 296 * 297 * @example 298 * var y = erfc( -1.0 ); 299 * // returns ~1.8427 300 * 301 * @example 302 * var y = erfc( 0.0 ); 303 * // returns 1.0 304 * 305 * @example 306 * var y = erfc( Infinity ); 307 * // returns 0.0 308 * 309 * @example 310 * var y = erfc( -Infinity ); 311 * // returns 2.0 312 * 313 * @example 314 * var y = erfc( NaN ); 315 * // returns NaN 316 */ 317 function erfc( x ) { 318 var sign; 319 var ax; 320 var z; 321 var r; 322 var s; 323 var y; 324 var p; 325 var q; 326 327 // Special case: NaN 328 if ( isnan( x ) ) { 329 return NaN; 330 } 331 // Special case: +infinity 332 if ( x === PINF ) { 333 return 0.0; 334 } 335 // Special case: -infinity 336 if ( x === NINF ) { 337 return 2.0; 338 } 339 // Special case: +-0 340 if ( x === 0.0 ) { 341 return 1.0; 342 } 343 if ( x < 0.0 ) { 344 sign = true; 345 ax = -x; 346 } else { 347 sign = false; 348 ax = x; 349 } 350 // |x| < 0.84375 351 if ( ax < 0.84375 ) { 352 if ( ax < SMALL ) { 353 return 1.0 - x; // raise inexact 354 } 355 z = x * x; 356 r = PPC + ( z*polyvalPP( z ) ); 357 s = QQC + ( z*polyvalQQ( z ) ); 358 y = r / s; 359 360 // x < 1/4 361 if ( x < 0.25 ) { 362 return 1.0 - ( x + (x*y) ); 363 } 364 r = x * y; 365 r += x - 0.5; 366 return 0.5 - r; 367 } 368 // 0.84375 <= |x| < 1.25 369 if ( ax < 1.25 ) { 370 s = ax - 1.0; 371 p = PAC + ( s*polyvalPA( s ) ); 372 q = QAC + ( s*polyvalQA( s ) ); 373 if ( sign ) { 374 return 1.0 + ERX + (p/q); 375 } 376 return 1.0 - ERX - (p/q); 377 } 378 // |x| < 28 379 if ( ax < 28.0 ) { 380 s = 1.0 / (ax*ax); 381 382 // |x| < 1/0.35 ~ 2.857143 383 if ( ax < 2.857142857142857 ) { 384 r = RAC + ( s*polyvalRA( s ) ); 385 s = SAC + ( s*polyvalSA( s ) ); 386 } 387 // |x| >= 1/0.35 ~ 2.857143 388 else { 389 // x < -6 390 if ( x < -6.0 ) { 391 return 2.0 - TINY; // raise inexact 392 } 393 r = RBC + ( s*polyvalRB( s ) ); 394 s = SBC + ( s*polyvalSB( s ) ); 395 } 396 z = setLowWord( ax, 0 ); // pseudo-single (20-bit) precision x 397 r = exp( -(z*z) - 0.5625 ) * exp( ((z-ax)*(z+ax)) + (r/s) ); 398 if ( sign ) { 399 return 2.0 - (r/ax); 400 } 401 return r/ax; 402 } 403 if ( sign ) { 404 return 2.0 - TINY; // raise inexact; ~2 405 } 406 return TINY * TINY; // raise inexact; ~0 407 } 408 409 410 // EXPORTS // 411 412 module.exports = erfc;