atanh.js (3207B)
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/e_atanh.c?view=markup}. The implementation follows the original, but has been modified for JavaScript. 22 * 23 * ```text 24 * Copyright (C) 2004 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 log1p = require( './../../../../base/special/log1p' ); 39 var PINF = require( '@stdlib/constants/float64/pinf' ); 40 var NINF = require( '@stdlib/constants/float64/ninf' ); 41 42 43 // VARIABLES // 44 45 var NEAR_ZERO = 1.0 / (1 << 28); // 2**-28 46 47 48 // MAIN // 49 50 /** 51 * Computes the hyperbolic arctangent of a number. 52 * 53 * ## Method 54 * 55 * 1. Reduce \\( x \\) to positive by \\( \operatorname{atanh}(-x) = -\operatorname{atanh}(x) \\) 56 * 57 * 2. For \\( x \ge 0.5 \\), we calculate 58 * 59 * ```tex 60 * \operatorname{atanh}(x) = \frac{1}{2} \cdot \log\left( 1 + \tfrac{2x}{1-x} \right) = \frac{1}{2} \cdot \operatorname{log1p}\left( 2 \tfrac{x}{1-x} \right) 61 * ``` 62 * 63 * For \\( x < 0.5 \\), we have 64 * 65 * ```tex 66 * \operatorname{atanh}(x) = \frac{1}{2} \cdot \operatorname{log1p}\left( 2x + \tfrac{2x^2}{1-x} \right) 67 * ``` 68 * 69 * ## Special Cases 70 * 71 * ```tex 72 * \begin{align*} 73 * \operatorname{atanh}(\mathrm{NaN}) &= \mathrm{NaN}\\ 74 * \operatorname{atanh}(1.0) &= \infty \\ 75 * \operatorname{atanh}(-1.0) &= -\infty \\ 76 * \end{align*} 77 * ``` 78 * 79 * @param {number} x - input value 80 * @returns {number} hyperbolic arctangent (in radians) 81 * 82 * @example 83 * var v = atanh( 0.0 ); 84 * // returns 0.0 85 * 86 * @example 87 * var v = atanh( 0.9 ); 88 * // returns ~1.472 89 * 90 * @example 91 * var v = atanh( 1.0 ); 92 * // returns Infinity 93 * 94 * @example 95 * var v = atanh( -1.0 ); 96 * // returns -Infinity 97 * 98 * @example 99 * var v = atanh( NaN ); 100 * // returns NaN 101 */ 102 function atanh( x ) { 103 var sgn; 104 var t; 105 if ( isnan( x ) ) { 106 return NaN; 107 } 108 if ( x < -1.0 || x > 1.0 ) { 109 return NaN; 110 } 111 if ( x === 1.0 ) { 112 return PINF; 113 } 114 if ( x === -1.0 ) { 115 return NINF; 116 } 117 if ( x < 0.0 ) { 118 sgn = true; 119 x = -x; 120 } 121 // Case: |x| < 2**-28 122 if ( x < NEAR_ZERO ) { 123 return ( sgn ) ? -x : x; 124 } 125 if ( x < 0.5 ) { 126 t = x + x; 127 t = 0.5 * log1p( t + ( t*x/(1-x) ) ); 128 } else { 129 t = 0.5 * log1p( (x+x) / (1-x) ); 130 } 131 return ( sgn ) ? -t : t; 132 } 133 134 135 // EXPORTS // 136 137 module.exports = atanh;