1use crate::common::f_fmla;
30use crate::cube_roots::cbrtf::halley_refine_d;
31use crate::double_double::DoubleDouble;
32use crate::exponents::fast_ldexp;
33use crate::polyeval::f_polyeval4;
34
35pub fn f_cbrt(x: f64) -> f64 {
39 static ESCALE: [f64; 3] = [
41 1.0,
42 f64::from_bits(0x3ff428a2f98d728b),
43 f64::from_bits(0x3ff965fea53d6e3d),
44 ];
45
46 let bits = x.to_bits();
47 let mut exp = ((bits >> 52) & 0x7ff) as i32;
48 let mut mant = bits & ((1u64 << 52) - 1);
49
50 if exp == 0x7ff || x == 0.0 {
51 return x + x;
52 }
53
54 if exp == 0 && x != 0.0 {
56 let norm = x * f64::from_bits(0x4350000000000000); let norm_bits = norm.to_bits();
58 mant = norm_bits & ((1u64 << 52) - 1);
59 exp = ((norm_bits >> 52) & 0x7ff) as i32 - 54;
60 }
61
62 exp -= 1023;
63
64 mant |= 0x3ff << 52;
65 let m = f64::from_bits(mant);
66
67 let p = f_polyeval4(
75 m,
76 f64::from_bits(0x3fe1b0babceeaafa),
77 f64::from_bits(0x3fe2c9a3e8e06a3c),
78 f64::from_bits(0xbfc4dc30afb71885),
79 f64::from_bits(0x3f97a8d3e05458e4),
80 );
81
82 let q = exp.div_euclid(3);
85 let rem_scale = exp.rem_euclid(3);
86
87 let z = p * ESCALE[rem_scale as usize];
88
89 let mm = fast_ldexp(m, rem_scale); let r = 1.0 / mm;
92
93 let y0 = halley_refine_d(z, mm);
96 let d2y = DoubleDouble::from_exact_mult(y0, y0);
97 let d3y = DoubleDouble::quick_mult_f64(d2y, y0);
98 let h = ((d3y.hi - mm) + d3y.lo) * r;
102 let y = f_fmla(-f64::from_bits(0x3fd5555555555555), y0 * h, y0);
104
105 f64::copysign(fast_ldexp(y, q), x)
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_cbrt() {
114 assert_eq!(f_cbrt(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005432309223745),
115 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017579026781511548);
116 assert_eq!(f_cbrt(1.225158611559834), 1.0700336588124544);
117 assert_eq!(f_cbrt(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139491540182158), 1.1173329935611586e-103);
118 assert_eq!(f_cbrt(27.0), 3.0);
119 assert_eq!(f_cbrt(64.0), 4.0);
120 assert_eq!(f_cbrt(125.0), 5.0);
121 assert_eq!(f_cbrt(216.0), 6.0);
122 assert_eq!(f_cbrt(343.0), 7.0);
123 assert_eq!(f_cbrt(512.0), 8.0);
124 assert_eq!(f_cbrt(729.0), 9.0);
125 assert_eq!(f_cbrt(-729.0), -9.0);
126 assert_eq!(f_cbrt(-512.0), -8.0);
127 assert_eq!(f_cbrt(-343.0), -7.0);
128 assert_eq!(f_cbrt(-216.0), -6.0);
129 assert_eq!(f_cbrt(-125.0), -5.0);
130 assert_eq!(f_cbrt(-64.0), -4.0);
131 assert_eq!(f_cbrt(-27.0), -3.0);
132 assert_eq!(f_cbrt(0.0), 0.0);
133 assert_eq!(f_cbrt(f64::INFINITY), f64::INFINITY);
134 assert_eq!(f_cbrt(f64::NEG_INFINITY), f64::NEG_INFINITY);
135 assert!(f_cbrt(f64::NAN).is_nan());
136 }
137}