macro_rules! wide_lit {
($T:ty, $s:literal) => {
match <$T>::from_str_radix($s, 10) {
::core::result::Result::Ok(v) => v,
::core::result::Result::Err(_) => {
panic!(concat!("wide_roots: invalid base-10 literal ", $s))
}
}
};
}
macro_rules! decl_wide_roots {
($Type:ident, $Storage:ty, $SqrtWide:ty, $CbrtWide:ty) => {
impl<const SCALE: u32> $Type<SCALE> {
#[inline]
#[must_use]
pub fn sqrt_strict(self) -> Self {
self.sqrt_strict_with($crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
#[inline]
#[must_use]
pub fn sqrt_strict_with(self, mode: $crate::support::rounding::RoundingMode) -> Self {
Self($crate::policy::sqrt::dispatch::<_, SCALE>(self.0, mode))
}
#[inline]
#[must_use]
pub fn cbrt_strict(self) -> Self {
self.cbrt_strict_with($crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
#[inline]
#[must_use]
pub fn cbrt_strict_with(self, mode: $crate::support::rounding::RoundingMode) -> Self {
Self($crate::policy::cbrt::dispatch::<_, SCALE>(self.0, mode))
}
#[cfg(all(feature = "strict", not(feature = "fast")))]
#[inline]
#[must_use]
pub fn sqrt(self) -> Self {
self.sqrt_strict()
}
#[cfg(all(feature = "strict", not(feature = "fast")))]
#[inline]
#[must_use]
pub fn cbrt(self) -> Self {
self.cbrt_strict()
}
#[inline]
#[must_use]
pub fn hypot_strict(self, other: Self) -> Self {
self.hypot_strict_with(other, $crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
#[inline]
#[must_use]
pub fn hypot_strict_with(
self,
other: Self,
mode: $crate::support::rounding::RoundingMode,
) -> Self {
Self($crate::policy::hypot::dispatch::<_, SCALE>(self.0, other.0, mode))
}
}
};
}
pub(crate) use {decl_wide_roots, wide_lit};
#[cfg(all(
test,
not(feature = "fast"),
any(feature = "d76", feature = "d153", feature = "d307")
))]
mod tests {
#[test]
fn sqrt_perfect_squares_are_exact() {
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(4_i128).unwrap().sqrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::try_from(2_i128).unwrap());
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(9_i128).unwrap().sqrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::try_from(3_i128).unwrap());
#[cfg(feature = "d76")]
assert_eq!(
crate::D::<crate::int::types::Int<4>, 6>::try_from(144_i128).unwrap().sqrt_strict(),
crate::D::<crate::int::types::Int<4>, 6>::try_from(12_i128).unwrap()
);
#[cfg(feature = "d153")]
assert_eq!(
crate::D::<crate::int::types::Int<8>, 6>::try_from(25_i128).unwrap().sqrt_strict(),
crate::D::<crate::int::types::Int<8>, 6>::try_from(5_i128).unwrap()
);
#[cfg(feature = "d307")]
assert_eq!(
crate::D::<crate::int::types::Int<16>, 6>::try_from(81_i128).unwrap().sqrt_strict(),
crate::D::<crate::int::types::Int<16>, 6>::try_from(9_i128).unwrap()
);
}
#[cfg(any(feature = "d76", feature = "d307"))]
#[test]
fn sqrt_zero_and_negative_saturate() {
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::ZERO.sqrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::ZERO);
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(-4_i128).unwrap().sqrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::ZERO);
#[cfg(feature = "d307")]
assert_eq!(crate::D::<crate::int::types::Int<16>, 6>::try_from(-1_i128).unwrap().sqrt_strict(), crate::D::<crate::int::types::Int<16>, 6>::ZERO);
}
#[test]
fn cbrt_perfect_cubes_are_exact() {
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(8_i128).unwrap().cbrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::try_from(2_i128).unwrap());
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(27_i128).unwrap().cbrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::try_from(3_i128).unwrap());
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::try_from(-8_i128).unwrap().cbrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::try_from(-2_i128).unwrap());
#[cfg(feature = "d153")]
assert_eq!(
crate::D::<crate::int::types::Int<8>, 6>::try_from(125_i128).unwrap().cbrt_strict(),
crate::D::<crate::int::types::Int<8>, 6>::try_from(5_i128).unwrap()
);
#[cfg(feature = "d307")]
assert_eq!(
crate::D::<crate::int::types::Int<16>, 6>::try_from(-64_i128).unwrap().cbrt_strict(),
crate::D::<crate::int::types::Int<16>, 6>::try_from(-4_i128).unwrap()
);
}
#[test]
fn cbrt_zero_is_zero() {
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 6>::ZERO.cbrt_strict(), crate::D::<crate::int::types::Int<4>, 6>::ZERO);
#[cfg(feature = "d153")]
assert_eq!(crate::D::<crate::int::types::Int<8>, 6>::ZERO.cbrt_strict(), crate::D::<crate::int::types::Int<8>, 6>::ZERO);
#[cfg(feature = "d307")]
assert_eq!(crate::D::<crate::int::types::Int<16>, 6>::ZERO.cbrt_strict(), crate::D::<crate::int::types::Int<16>, 6>::ZERO);
}
#[cfg(feature = "d76")]
#[test]
fn wide_roots_match_d38() {
for raw in [2i64, 3, 5, 7, 10, 123, 1_000, 999_983] {
let narrow = crate::D::<crate::int::types::Int<2>, 6>::try_from(raw).unwrap();
let wide: crate::D<crate::int::types::Int<4>, 6> = narrow.into();
let narrow_sqrt: crate::D<crate::int::types::Int<4>, 6> = narrow.sqrt_strict().into();
assert_eq!(wide.sqrt_strict(), narrow_sqrt, "sqrt mismatch for {raw}");
let narrow_cbrt: crate::D<crate::int::types::Int<4>, 6> = narrow.cbrt_strict().into();
assert_eq!(wide.cbrt_strict(), narrow_cbrt, "cbrt mismatch for {raw}");
}
}
#[cfg(any(feature = "d76", feature = "d307"))]
#[test]
fn sqrt_cbrt_at_wide_only_scale() {
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 50>::try_from(4_i128).unwrap().sqrt_strict(), crate::D::<crate::int::types::Int<4>, 50>::try_from(2_i128).unwrap());
#[cfg(feature = "d76")]
assert_eq!(crate::D::<crate::int::types::Int<4>, 50>::try_from(8_i128).unwrap().cbrt_strict(), crate::D::<crate::int::types::Int<4>, 50>::try_from(2_i128).unwrap());
#[cfg(feature = "d307")]
assert_eq!(
crate::D::<crate::int::types::Int<16>, 150>::try_from(9_i128).unwrap().sqrt_strict(),
crate::D::<crate::int::types::Int<16>, 150>::try_from(3_i128).unwrap()
);
#[cfg(feature = "d307")]
assert_eq!(
crate::D::<crate::int::types::Int<16>, 150>::try_from(27_i128).unwrap().cbrt_strict(),
crate::D::<crate::int::types::Int<16>, 150>::try_from(3_i128).unwrap()
);
}
}