2,863 bytes · the TypeScript implementation · view raw
// Derived from fdlibm s_atan.c.// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.// Developed at SunSoft, a Sun Microsystems, Inc. business.// Permission to use, copy, modify, and distribute this// software is freely granted, provided that this notice// is preserved.// fdlibm s_atan.c (Sun Microsystems, 1993). atan of 0.5, 1, 1.5 and infinity,// each split into a high and a low part so the sum carries more than 53 bits.const ATAN_HI = [
4.63647609000806093515e-01,
7.85398163397448278999e-01,
9.82793723247329054082e-01,
1.57079632679489655800e+00,
];
const ATAN_LO = [
2.26987774529616870924e-17,
3.06161699786838301793e-17,
1.39033110312309984516e-17,
6.12323399573676603587e-17,
];
const AT = [
3.33333333333329318027e-01,
-1.99999999998764832476e-01,
1.42857142725034663711e-01,
-1.11111104054623557880e-01,
9.09088713343650656196e-02,
-7.69187620504482999495e-02,
6.66107313738753120669e-02,
-5.83357013379057348645e-02,
4.97687799461593236017e-02,
-3.65315727442169155270e-02,
1.62858201153657823623e-02,
];
const TWO_POW_66 = 73786976294838206464;
const TWO_POW_M29 = 1.862645149230957e-9;
/** * Arctangent in radians using only +, -, * and /, in the same order as the * Python and Rust versions, so all three return the same double. Math.atan * comes from each platform's maths library and may differ in the last bit. * * fdlibm's method: reduce |x| against atan(0.5), atan(1), atan(1.5) or pi/2, * then an odd polynomial on the remainder. fdlibm picks the interval from the * high word of the double; comparing |x| with the same boundaries (7/16, * 11/16, 19/16, 39/16, 2^66, 2^-29) is exactly equivalent. */exportfunction atan(x: number): number {
if (typeof x !== "number" || !Number.isFinite(x)) {
thrownew RangeError(`x must be a finite number, received ${String(x)}`);
}
const negative = x < 0;
const a = negative ? -x : x;
if (a >= TWO_POW_66) {
const r = ATAN_HI[3] + ATAN_LO[3];
return negative ? -r : r;
}
let i: number;
let t = x;
if (a < 0.4375) {
// atan(x) rounds to x here; + 0 turns -0 into 0.if (a < TWO_POW_M29) return x + 0;
i = -1;
} else {
t = a;
if (a < 1.1875) {
if (a < 0.6875) {
i = 0;
t = (2.0 * t - 1.0) / (2.0 + t);
} else {
i = 1;
t = (t - 1.0) / (t + 1.0);
}
} elseif (a < 2.4375) {
i = 2;
t = (t - 1.5) / (1.0 + 1.5 * t);
} else {
i = 3;
t = -1.0 / t;
}
}
const z = t * t;
const w = z * z;
const s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10])))));
const s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9]))));
if (i < 0) return t - t * (s1 + s2);
const r = ATAN_HI[i] - ((t * (s1 + s2) - ATAN_LO[i]) - t);
return negative ? -r : r;
}