use crate::support::rounding::RoundingMode;
use crate::wide_int::WideStorage;
#[inline]
#[must_use]
pub(crate) fn sqrt<S, W>(raw: S, scale: u32, mode: RoundingMode) -> S
where
S: WideStorage,
W: WideStorage,
{
if raw <= S::ZERO {
return S::ZERO;
}
let n: W = raw.resize_to::<W>() * W::TEN.pow(scale);
let q: W = n.isqrt();
let diff: W = n - q * q;
let halfway_round_up = diff > q;
let diff_nonzero = diff != W::ZERO;
let bump = match mode {
RoundingMode::HalfToEven
| RoundingMode::HalfAwayFromZero
| RoundingMode::HalfTowardZero => halfway_round_up,
RoundingMode::Trunc | RoundingMode::Floor => false,
RoundingMode::Ceiling => diff_nonzero,
};
let q = if bump { q + W::ONE } else { q };
q.resize_to::<S>()
}
macro_rules! decl_sqrt_kernel_shim {
($name:ident, $Storage:ty, $SqrtWide:ty) => {
#[inline]
#[must_use]
pub(crate) fn $name(raw: $Storage, scale: u32, mode: RoundingMode) -> $Storage {
sqrt::<$Storage, $SqrtWide>(raw, scale, mode)
}
};
}
#[cfg(any(feature = "d57", feature = "wide"))]
decl_sqrt_kernel_shim!(sqrt_d57, crate::wide_int::Int192, crate::wide_int::Int384);
#[cfg(any(feature = "d76", feature = "wide"))]
decl_sqrt_kernel_shim!(sqrt_d76, crate::wide_int::Int256, crate::wide_int::Int512);
#[cfg(any(feature = "d115", feature = "wide"))]
decl_sqrt_kernel_shim!(sqrt_d115, crate::wide_int::Int384, crate::wide_int::Int768);
#[cfg(any(feature = "d153", feature = "wide"))]
decl_sqrt_kernel_shim!(sqrt_d153, crate::wide_int::Int512, crate::wide_int::Int1024);
#[cfg(any(feature = "d230", feature = "wide"))]
decl_sqrt_kernel_shim!(sqrt_d230, crate::wide_int::Int768, crate::wide_int::Int1536);
#[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
decl_sqrt_kernel_shim!(sqrt_d307, crate::wide_int::Int1024, crate::wide_int::Int2048);
#[cfg(any(feature = "d462", feature = "x-wide"))]
decl_sqrt_kernel_shim!(sqrt_d462, crate::wide_int::Int1536, crate::wide_int::Int3072);
#[cfg(any(feature = "d616", feature = "x-wide"))]
decl_sqrt_kernel_shim!(sqrt_d616, crate::wide_int::Int2048, crate::wide_int::Int4096);
#[cfg(any(feature = "d924", feature = "xx-wide"))]
decl_sqrt_kernel_shim!(sqrt_d924, crate::wide_int::Int3072, crate::wide_int::Int6144);
#[cfg(any(feature = "d1232", feature = "xx-wide"))]
decl_sqrt_kernel_shim!(sqrt_d1232, crate::wide_int::Int4096, crate::wide_int::Int8192);