atan.js (3508B)
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 original C code, long comment, copyright, license, and constants are from [Cephes]{@link http://www.netlib.org/cephes}. The implementation follows the original, but has been modified for JavaScript. 22 * 23 * ```text 24 * Copyright 1984, 1995, 2000 by Stephen L. Moshier 25 * 26 * Some software in this archive may be from the book _Methods and Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster International, 1989) or from the Cephes Mathematical Library, a commercial product. In either event, it is copyrighted by the author. What you see here may be used freely but it comes with no support or guarantee. 27 * 28 * Stephen L. Moshier 29 * moshier@na-net.ornl.gov 30 * ``` 31 */ 32 33 'use strict'; 34 35 // MODULES // 36 37 var isnan = require( './../../../../base/assert/is-nan' ); 38 var PINF = require( '@stdlib/constants/float64/pinf' ); 39 var PIO2 = require( '@stdlib/constants/float64/half-pi' ); 40 var PIO4 = require( '@stdlib/constants/float64/fourth-pi' ); 41 var NINF = require( '@stdlib/constants/float64/ninf' ); 42 var polyvalP = require( './polyval_p.js' ); 43 var polyvalQ = require( './polyval_q.js' ); 44 45 46 // VARIABLES // 47 48 var MOREBITS = 6.123233995736765886130e-17; // pi/2 = PIO2 + MOREBITS. 49 var T3P8 = 2.41421356237309504880; // tan( 3*pi/8 ) 50 51 52 // MAIN // 53 54 /** 55 * Computes the arctangent of a number. 56 * 57 * ## Method 58 * 59 * - Range reduction is from three intervals into the interval from 0 to 0.66. The approximant uses a rational function of degree 4/5 of the form 60 * 61 * ```tex 62 * x + x^3 \frac{P(x)}{Q(x)} 63 * ``` 64 * 65 * ## Notes 66 * 67 * - Relative error: 68 * 69 * | arithmetic | domain | # trials | peak | rms | 70 * |:-----------|:--------|:---------|:--------|:--------| 71 * | DEC | -10, 10 | 50000 | 2.4e-17 | 8.3e-18 | 72 * | IEEE | -10, 10 | 10^6 | 1.8e-16 | 5.0e-17 | 73 * 74 * @param {number} x - input value 75 * @returns {number} arctangent (in radians) 76 * 77 * @example 78 * var v = atan( 0.0 ); 79 * // returns ~0.0 80 * 81 * @example 82 * var PI = require( '@stdlib/constants/float64/pi' ); 83 * 84 * var v = atan( -PI/4.0 ); 85 * // returns ~-0.666 86 * 87 * @example 88 * var PI = require( '@stdlib/constants/float64/pi' ); 89 * 90 * var v = atan( PI/4.0 ); 91 * // returns ~0.666 92 * 93 * @example 94 * var v = atan( NaN ); 95 * // returns NaN 96 */ 97 function atan( x ) { 98 var flg; 99 var sgn; 100 var y; 101 var z; 102 if ( isnan( x ) || x === 0.0 ) { 103 return x; 104 } 105 if ( x === PINF ) { 106 return PIO2; 107 } 108 if ( x === NINF ) { 109 return -PIO2; 110 } 111 if ( x < 0.0 ) { 112 sgn = true; 113 x = -x; 114 } 115 // Range reduction: 116 flg = 0; 117 if ( x > T3P8 ) { 118 y = PIO2; 119 flg = 1; 120 x = -( 1.0/x ); 121 } 122 else if ( x <= 0.66 ) { 123 y = 0.0; 124 } 125 else { 126 y = PIO4; 127 flg = 2; 128 x = (x-1.0) / (x+1.0); 129 } 130 z = x * x; 131 z = z*polyvalP( z ) / polyvalQ( z ); 132 z = ( x*z ) + x; 133 if ( flg === 2 ) { 134 z += 0.5 * MOREBITS; 135 } 136 else if ( flg === 1 ) { 137 z += MOREBITS; 138 } 139 y += z; 140 return ( sgn ) ? -y : y; 141 } 142 143 144 // EXPORTS // 145 146 module.exports = atan;