use super::rem_pio2_large::rem_pio2_large;
const EPS: f64 = 2.2204460492503131e-16;
const TO_INT: f64 = 1.5 / EPS;
const INV_PIO2: f64 = 6.36619772367581382433e-01;
const PIO2_1: f64 = 1.57079632673412561417e+00;
const PIO2_1T: f64 = 6.07710050650619224932e-11;
const PIO2_2: f64 = 6.07710050630396597660e-11;
const PIO2_2T: f64 = 2.02226624879595063154e-21;
const PIO2_3: f64 = 2.02226624871116645580e-21;
const PIO2_3T: f64 = 8.47842766036889956997e-32;
pub(crate) const fn rem_pio2(x: f64) -> (i32, f64, f64) {
let x1p24 = f64::from_bits(0x4170000000000000);
let sign = (f64::to_bits(x) >> 63) as i32;
let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;
const fn medium(x: f64, ix: u32) -> (i32, f64, f64) {
let tmp = x * INV_PIO2 + TO_INT;
let f_n = tmp - TO_INT;
let n = f_n as i32;
let mut r = x - f_n * PIO2_1;
let mut w = f_n * PIO2_1T;
let mut y0 = r - w;
let ui = f64::to_bits(y0);
let ey = (ui >> 52) as i32 & 0x7ff;
let ex = (ix >> 20) as i32;
if ex - ey > 16 {
let t = r;
w = f_n * PIO2_2;
r = t - w;
w = f_n * PIO2_2T - ((t - r) - w);
y0 = r - w;
let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff;
if ex - ey > 49 {
let t = r;
w = f_n * PIO2_3;
r = t - w;
w = f_n * PIO2_3T - ((t - r) - w);
y0 = r - w;
}
}
let y1 = (r - y0) - w;
(n, y0, y1)
}
if ix <= 0x400f6a7a {
if (ix & 0xfffff) == 0x921fb {
return medium(x, ix);
}
if ix <= 0x4002d97c {
if sign == 0 {
let z = x - PIO2_1;
let y0 = z - PIO2_1T;
let y1 = (z - y0) - PIO2_1T;
return (1, y0, y1);
} else {
let z = x + PIO2_1;
let y0 = z + PIO2_1T;
let y1 = (z - y0) + PIO2_1T;
return (-1, y0, y1);
}
} else if sign == 0 {
let z = x - 2.0 * PIO2_1;
let y0 = z - 2.0 * PIO2_1T;
let y1 = (z - y0) - 2.0 * PIO2_1T;
return (2, y0, y1);
} else {
let z = x + 2.0 * PIO2_1;
let y0 = z + 2.0 * PIO2_1T;
let y1 = (z - y0) + 2.0 * PIO2_1T;
return (-2, y0, y1);
}
}
if ix <= 0x401c463b {
if ix <= 0x4015fdbc {
if ix == 0x4012d97c {
return medium(x, ix);
}
if sign == 0 {
let z = x - 3.0 * PIO2_1;
let y0 = z - 3.0 * PIO2_1T;
let y1 = (z - y0) - 3.0 * PIO2_1T;
return (3, y0, y1);
} else {
let z = x + 3.0 * PIO2_1;
let y0 = z + 3.0 * PIO2_1T;
let y1 = (z - y0) + 3.0 * PIO2_1T;
return (-3, y0, y1);
}
} else {
if ix == 0x401921fb {
return medium(x, ix);
}
if sign == 0 {
let z = x - 4.0 * PIO2_1;
let y0 = z - 4.0 * PIO2_1T;
let y1 = (z - y0) - 4.0 * PIO2_1T;
return (4, y0, y1);
} else {
let z = x + 4.0 * PIO2_1;
let y0 = z + 4.0 * PIO2_1T;
let y1 = (z - y0) + 4.0 * PIO2_1T;
return (-4, y0, y1);
}
}
}
if ix < 0x413921fb {
return medium(x, ix);
}
if ix >= 0x7ff00000 {
let y0 = 0.0;
let y1 = y0;
return (0, y0, y1);
}
let mut ui = f64::to_bits(x);
ui &= (!1) >> 12;
ui |= (0x3ff + 23) << 52;
let mut z = f64::from_bits(ui);
let mut tx = [0.0; 3];
let mut i = 0;
while i < 2 {
tx[i] = z as i32 as f64;
z = (z - tx[i]) * x1p24;
i += 1;
}
tx[2] = z;
let mut i = 2;
while i != 0 && tx[i] == 0.0 {
i -= 1;
}
let mut ty = [0.0; 3];
let s: &[f64] = match i {
0 => &[tx[0]],
1 => &[tx[0], tx[1]],
2 => &[tx[0], tx[1], tx[2]],
_ => unreachable!(),
};
let n = rem_pio2_large(s, &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1);
if sign != 0 {
return (-n, -ty[0], -ty[1]);
}
(n, ty[0], ty[1])
}