#![cfg(any(feature = "d57", feature = "wide"))]
use crate::support::rounding::RoundingMode;
use crate::wide_int::{Int192, Int384, WideStorage};
const SCALE: u32 = 20;
#[cfg(feature = "std")]
#[inline]
fn icbrt_f64_seeded(n: Int384) -> Int384 {
let seed_f64 = n.as_f64().cbrt();
let seed = Int384::from_f64(seed_f64);
let x0 = if seed <= Int384::ZERO { Int384::ONE } else { seed };
let three = Int384::from_i128(3);
let mut x = (x0 + x0 + n / (x0 * x0)) / three;
if x <= Int384::ZERO {
x = Int384::ONE;
}
loop {
let y = (x + x + n / (x * x)) / three;
if y >= x {
break x;
}
x = y;
}
}
#[inline]
#[must_use]
pub(crate) fn cbrt(raw: Int192, mode: RoundingMode) -> Int192 {
#[cfg(not(feature = "std"))]
{
return super::generic_wide::cbrt::<Int192, Int384>(raw, SCALE, mode);
}
#[cfg(feature = "std")]
{
if raw == Int192::ZERO {
return Int192::ZERO;
}
let zero = Int384::ZERO;
let one = Int384::ONE;
let widened: Int384 = raw.resize_to::<Int384>();
let negative = widened < zero;
let mag = if negative { -widened } else { widened };
let n: Int384 = mag * Int384::TEN.pow(2 * SCALE);
let q = icbrt_f64_seeded(n);
let eight_n = n << 3u32;
let t = q + q + one;
let cube = t * t * t;
let halfway_geq = eight_n >= cube;
let halfway_gt = eight_n > cube;
let tie = halfway_geq && !halfway_gt;
let two_q = q + q;
let eight_q_cubed = if q == zero { zero } else { two_q * two_q * two_q };
let residual_nonzero = eight_n > eight_q_cubed;
let q_is_odd = (q % (one + one)) != zero;
let bump = match mode {
RoundingMode::HalfToEven => halfway_gt || (tie && q_is_odd),
RoundingMode::HalfAwayFromZero => halfway_geq,
RoundingMode::HalfTowardZero => halfway_gt,
RoundingMode::Trunc => false,
RoundingMode::Floor => negative && residual_nonzero,
RoundingMode::Ceiling => !negative && residual_nonzero,
};
let q = if bump { q + one } else { q };
let signed = if negative { -q } else { q };
signed.resize_to::<Int192>()
}
}
const _: fn() = || {
let _: fn(Int192, RoundingMode) -> Int192 = cbrt;
let _ = <Int384 as WideStorage>::BITS;
};