1use crate::common::f_fmla;
30use crate::double_double::DoubleDouble;
31use crate::sincospi::reduce_pi_64;
32use crate::tangent::tanpi::tanpi_eval;
33use crate::tangent::tanpi_table::TANPI_K_PI_OVER_64;
34
35#[cold]
36fn cotpi_hard(x: f64, tan_k: DoubleDouble) -> DoubleDouble {
37 const C: [(u64, u64); 6] = [
38 (0x3ca1a62632712fc8, 0x400921fb54442d18),
39 (0xbcc052338fbb4528, 0x4024abbce625be53),
40 (0x3ced42454c5f85b3, 0x404466bc6775aad9),
41 (0xbd00c7d6a971a560, 0x40645fff9b4b244d),
42 (0x3d205970eff53274, 0x40845f46e96c3a0b),
43 (0xbd3589489ad24fc4, 0x40a4630551cd123d),
44 ];
45 let x2 = DoubleDouble::from_exact_mult(x, x);
46 let mut tan_y = DoubleDouble::quick_mul_add(
47 x2,
48 DoubleDouble::from_bit_pair(C[5]),
49 DoubleDouble::from_bit_pair(C[4]),
50 );
51 tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[3]));
52 tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[2]));
53 tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[1]));
54 tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[0]));
55 tan_y = DoubleDouble::quick_mult_f64(tan_y, x);
56
57 let num = DoubleDouble::full_dd_add(tan_y, tan_k);
59 let den = DoubleDouble::mul_add_f64(tan_y, -tan_k, 1.);
61 DoubleDouble::div(den, num)
63}
64
65pub fn f_cotpi(x: f64) -> f64 {
69 if x == 0. {
70 return if x.is_sign_negative() {
71 f64::NEG_INFINITY
72 } else {
73 f64::INFINITY
74 };
75 }
76 let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff;
77 if ax >= (0x7ffu64 << 52) {
78 if ax > (0x7ffu64 << 52) {
80 return x + x;
81 } return f64::NAN; }
84 let e: i32 = (ax >> 52) as i32 - 1023;
85 if e > 0 {
86 if e >= 52 {
87 return f64::copysign(f64::INFINITY, x);
89 }
90 let m = (ax & ((1u64 << 52) - 1)) | (1u64 << 52); let shift = 52 - e;
93
94 let frac = m & ((1u64 << shift) - 1);
95 if frac == (1u64 << (shift - 1)) {
96 return f64::copysign(0., x);
98 }
99 }
100
101 if ax <= 0x3cb0000000000000 {
102 const ONE_OVER_PI: DoubleDouble =
105 DoubleDouble::from_bit_pair((0xbc76b01ec5417056, 0x3fd45f306dc9c883));
106 if ax <= 0x3ca0000000000000 {
107 let e: i32 = (ax >> 52) as i32;
109 let sc = f64::from_bits((2045i64 - e as i64).wrapping_shl(52) as u64);
110 let dx = x * sc;
111 let q0 = DoubleDouble::quick_mult(ONE_OVER_PI, DoubleDouble::from_quick_recip(dx));
112 let r = q0.to_f64() * sc;
113 return r;
114 }
115 let q0 = DoubleDouble::quick_mult(ONE_OVER_PI, DoubleDouble::from_quick_recip(x));
116 let r = q0.to_f64();
117 return r;
118 }
119
120 let (y, k) = reduce_pi_64(x);
122
123 if y == 0.0 {
124 let km = (k.abs() & 63) as i32; match km {
127 0 => return f64::copysign(f64::INFINITY, x), 32 => return f64::copysign(0., x), 16 => return f64::copysign(1.0, x), 48 => return -f64::copysign(1.0, x), _ => {}
132 }
133 }
134
135 let tan_k = DoubleDouble::from_bit_pair(TANPI_K_PI_OVER_64[((k as u64) & 127) as usize]);
136
137 let tan_y = tanpi_eval(y);
140 let num = DoubleDouble::add(tan_k, tan_y);
142 let den = DoubleDouble::mul_add_f64(tan_y, -tan_k, 1.);
144 let tan_value = DoubleDouble::div(den, num);
146
147 let err = f_fmla(
148 tan_value.hi,
149 f64::from_bits(0x3bf0000000000000), f64::from_bits(0x3b60000000000000), );
152 let ub = tan_value.hi + (tan_value.lo + err);
153 let lb = tan_value.hi + (tan_value.lo - err);
154 if ub == lb {
155 return tan_value.to_f64();
156 }
157 cotpi_hard(y, tan_k).to_f64()
158}
159
160#[inline]
161pub(crate) fn cotpi_core(x: f64) -> DoubleDouble {
162 let (y, k) = reduce_pi_64(x);
164
165 let tan_k = DoubleDouble::from_bit_pair(TANPI_K_PI_OVER_64[((k as u64) & 127) as usize]);
166
167 let tan_y = tanpi_eval(y);
170 let num = DoubleDouble::add(tan_k, tan_y);
172 let den = DoubleDouble::mul_add_f64(tan_y, -tan_k, 1.);
174 DoubleDouble::div(den, num)
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn test_cotpi() {
184 assert_eq!(f_cotpi(3.382112265043898e-306), 9.411570676518013e304);
185 assert_eq!(f_cotpi(0.0431431231), 7.332763436038805);
186 assert_eq!(f_cotpi(-0.0431431231), -7.332763436038805);
187 assert_eq!(f_cotpi(0.52324), -0.07314061937774036);
188 assert!(f_cotpi(f64::INFINITY).is_nan());
189 assert!(f_cotpi(f64::NAN).is_nan());
190 assert!(f_cotpi(f64::NEG_INFINITY).is_nan());
191 }
192}