///|
/// Compute arctangent of `x`
///
/// # Examples
///
/// ```moonbit nocheck
/// assert_eq(atan(0), 0)
/// assert_eq(atan(1), 0.7853981633974483)
/// assert_eq(atan(2), 1.1071487177940904)
/// assert_eq(atan(-1),-0.7853981633974483)
/// assert_eq(atan(-2),-1.1071487177940904)
/// assert_eq(atan(@double.infinity), 1.5707963267948966)
/// assert_eq(atan(@double.neg_infinity), -1.5707963267948966)
/// ```
///
/// # Accuracy
///
/// 1 ulp (unit in the last place).
///
/// # Special Cases
///
/// 1. atan(NaN) = NaN
/// 2. atan(+Inf) = +π/2
/// 3. atan(-Inf) = -π/2
pub fn atan(x : Double) -> Double {
if x.is_nan() || x == 0.0 {
return x
}
let atan_hi = [
4.63647609000806093515e-01, 7.85398163397448278999e-01, 9.82793723247329054082e-01,
1.57079632679489655800e+00,
]
let atan_lo = [
2.26987774529616870924e-17, 3.06161699786838301793e-17, 1.39033110312309984516e-17,
6.12323399573676603587e-17,
]
let a_t = [
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,
]
let one = 1.0
let huge = 1.0e300
let ix = __hi(x).reinterpret_as_int() & 0x7fffffff
let mut id = 0
let mut z = 0.0
let mut w = 0.0
let mut x = x
let x_is_neg = x < 0.0
if ix >= 0x44100000 {
if x > 0 {
return atan_hi[3] + atan_lo[3]
} else {
return -atan_hi[3] - atan_lo[3]
}
}
if ix < 0x3fdc0000 {
if ix < 0x3e200000 {
if huge + x > one {
return x
}
}
id = -1
} else {
x = x.abs()
if ix < 0x3ff30000 {
if ix < 0x3fe60000 {
id = 0
x = (2.0 * x - one) / (2.0 + x)
} else {
id = 1
x = (x - one) / (x + one)
}
} else if ix < 0x40038000 {
id = 2
x = (x - 1.5) / (one + 1.5 * x)
} else {
id = 3
x = -1.0 / x
}
}
z = x * x
w = z * z
let s1 = z *
(
a_t[0] +
w * (a_t[2] + w * (a_t[4] + w * (a_t[6] + w * (a_t[8] + w * a_t[10]))))
)
let s2 = w *
(a_t[1] + w * (a_t[3] + w * (a_t[5] + w * (a_t[7] + w * a_t[9]))))
if id < 0 {
x - x * (s1 + s2)
} else {
z = atan_hi[id] - (x * (s1 + s2) - atan_lo[id] - x)
if x_is_neg {
-z
} else {
z
}
}
}
///|
test "atan" {
fn assert_atan_ulp(input, expect) raise {
assert_ulp(expect, atan(input), ATAN_MAX_ULP)
}
assert_atan_ulp(0, 0)
assert_atan_ulp(1, 0.7853981633974483)
assert_atan_ulp(2, 1.1071487177940906)
assert_atan_ulp(3, 1.2490457723982544)
assert_atan_ulp(4, 1.3258176636680326)
assert_atan_ulp(5, 1.373400766945016)
assert_atan_ulp(6, 1.4056476493802699)
assert_atan_ulp(7, 1.4288992721907328)
assert_atan_ulp(8, 1.446441332248135)
assert_atan_ulp(9, 1.460139105621001)
assert_atan_ulp(10, 1.4711276743037345)
assert_atan_ulp(11, 1.4801364395941514)
assert_atan_ulp(12, 1.4876550949064553)
assert_atan_ulp(13, 1.4940244355251187)
assert_atan_ulp(14, 1.4994888620096063)
assert_atan_ulp(15, 1.5042281630190728)
assert_atan_ulp(-1, -0.7853981633974483)
assert_atan_ulp(-2, -1.1071487177940906)
assert_atan_ulp(-3, -1.2490457723982544)
assert_atan_ulp(-4, -1.3258176636680326)
assert_atan_ulp(-5, -1.373400766945016)
assert_atan_ulp(-6, -1.4056476493802699)
assert_atan_ulp(-7, -1.4288992721907328)
assert_atan_ulp(-8, -1.446441332248135)
assert_atan_ulp(-9, -1.460139105621001)
assert_atan_ulp(-10, -1.4711276743037345)
assert_atan_ulp(-11, -1.4801364395941514)
assert_atan_ulp(-12, -1.4876550949064553)
assert_atan_ulp(-13, -1.4940244355251187)
assert_atan_ulp(-14, -1.4994888620096063)
assert_atan_ulp(-15, -1.5042281630190728)
assert_atan_ulp(0.12, 0.11942892601833845)
assert_atan_ulp(0.23, 0.2260683879938839)
assert_atan_ulp(0.34, 0.3277385067805555)
assert_atan_ulp(0.45, 0.4228539261329407)
assert_atan_ulp(0.56, 0.5104883219167758)
assert_atan_ulp(0.67, 0.590306746935372)
assert_atan_ulp(0.78, 0.6624262938331512)
assert_atan_ulp(0.89, 0.7272626879966904)
assert_atan_ulp(0.9, 0.7328151017865067)
assert_atan_ulp(-0.87, -0.7159911144163001)
assert_atan_ulp(-0.76, -0.6498704494119476)
assert_atan_ulp(-0.65, -0.5763752205911837)
assert_atan_ulp(-0.54, -0.49513326346840414)
assert_atan_ulp(-0.43, -0.40609805831761564)
assert_atan_ulp(-0.32, -0.3097029445424562)
assert_atan_ulp(-0.21, -0.206992194219821)
assert_atan_ulp(-0.1, -0.09966865249116204)
assert_atan_ulp(0.12345, 0.12282855068741544)
assert_atan_ulp(0.23456, 0.2303949468807241)
assert_atan_ulp(0.34567, 0.33281216252994195)
assert_atan_ulp(0.45678, 0.42847785122558607)
assert_atan_ulp(0.56789, 0.5164745097842471)
assert_atan_ulp(0.6789, 0.5964240851188558)
assert_atan_ulp(0.78901, 0.6680037059425237)
assert_atan_ulp(0.89012, 0.7273296445553981)
assert_atan_ulp(0.90123, 0.7334942443279985)
assert_atan_ulp(-0.98765, -0.7791848758086322)
assert_atan_ulp(-0.87654, -0.7197015466378203)
assert_atan_ulp(-0.76543, -0.6533033928690293)
assert_atan_ulp(-0.65432, -0.5794061351524672)
assert_atan_ulp(-0.54321, -0.49761521700698697)
assert_atan_ulp(-0.4321, -0.4078690083022377)
assert_atan_ulp(-0.32109, -0.3106913832920783)
assert_atan_ulp(-0.21098, -0.20793061638727955)
assert_atan_ulp(-0.10987, -0.10943107915405893)
assert_atan_ulp(1.234, 0.8897624489591893)
assert_atan_ulp(2.345, 1.1677072684050145)
assert_atan_ulp(3.456, 1.2891368759113806)
assert_atan_ulp(4.567, 1.3552362032374148)
assert_atan_ulp(5.678, 1.3964657470487327)
assert_atan_ulp(6.789, 1.4245508462879888)
assert_atan_ulp(7.89, 1.4447258005561798)
assert_atan_ulp(8.901, 1.4589185265134277)
assert_atan_ulp(9.012, 1.4602852545944818)
assert_atan_ulp(10.123, 1.4723308430472324)
assert_atan_ulp(11.234, 1.4820148389775378)
assert_atan_ulp(12.345, 1.489968353486419)
assert_atan_ulp(13.456, 1.4966163991626389)
assert_atan_ulp(-1.234, -0.8897624489591893)
assert_atan_ulp(-2.345, -1.1677072684050145)
assert_atan_ulp(-3.456, -1.2891368759113806)
assert_atan_ulp(-4.567, -1.3552362032374148)
assert_atan_ulp(-5.678, -1.3964657470487327)
assert_atan_ulp(-6.789, -1.4245508462879888)
assert_atan_ulp(-7.89, -1.4447258005561798)
assert_atan_ulp(-8.901, -1.4589185265134277)
assert_atan_ulp(-9.012, -1.4602852545944818)
assert_atan_ulp(-10.123, -1.4723308430472324)
assert_atan_ulp(-11.234, -1.4820148389775378)
assert_atan_ulp(-12.345, -1.489968353486419)
assert_atan_ulp(-13.456, -1.4966163991626389)
assert_atan_ulp(3.1415926, 1.2626272507486684)
assert_atan_ulp(2.7182818, 1.2182829016248764)
assert_atan_ulp(1.6180339, 1.0172219433679828)
assert_atan_ulp(1.4142136, 0.9553166306668107)
assert_atan_ulp(1.7320508, 1.0471975493043784)
assert_atan_ulp(0.5772157, 0.5234978428250526)
assert_atan_ulp(0.3010299, 0.2924013888286663)
assert_atan_ulp(0.6931472, 0.6061119478640076)
assert_atan_ulp(0.4342945, 0.40971675933419394)
assert_atan_ulp(0.0000001, 0.00000009999999999999966)
assert_atan_ulp(1000000000, 1.5707963257948967)
assert_atan_ulp(31415926535897.1234, 1.5707963267948648)
assert_atan_ulp(-27182818284590.5678, -1.57079632679486)
assert_atan_ulp(@double.max_value, 1.5707963267948966)
assert_atan_ulp(@double.min_value, -1.5707963267948966)
assert_atan_ulp(@double.infinity, 1.5707963267948966)
assert_atan_ulp(@double.neg_infinity, -1.5707963267948966)
assert_atan_ulp(@double.not_a_number, @double.not_a_number)
}