use crate::algos::sqrt;
use crate::int::types::traits::BigInt;
use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
use crate::int::types::Int;
use crate::support::rounding::RoundingMode;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Algorithm {
Newton,
MgDivide,
#[allow(dead_code)]
NewtonWithTableSeed,
#[allow(dead_code)]
Native,
#[allow(dead_code)]
Schoolbook,
}
#[derive(Clone, Copy)]
enum Select<const N: usize> {
ByAlgorithm(Algorithm),
#[allow(dead_code)]
ByValue(fn(&Int<N>) -> Algorithm),
}
const fn select<const N: usize, const SCALE: u32>() -> Select<N> {
match (N, SCALE) {
(1, _) => Select::ByAlgorithm(Algorithm::MgDivide),
(2, _) => Select::ByAlgorithm(Algorithm::MgDivide),
(3, _) | (4, _) => Select::ByAlgorithm(Algorithm::Native),
(6, s) if s >= 24 => Select::ByAlgorithm(Algorithm::Native), (8, s) if s >= 32 => Select::ByAlgorithm(Algorithm::Native), (12, s) if s >= 70 => Select::ByAlgorithm(Algorithm::Native), (16, s) if s >= 64 => Select::ByAlgorithm(Algorithm::Native), (24, s) if s >= 96 => Select::ByAlgorithm(Algorithm::Native), (32, s) if s >= 160 => Select::ByAlgorithm(Algorithm::Native), (48, s) if s >= 260 => Select::ByAlgorithm(Algorithm::Native), (64, s) if s >= 256 => Select::ByAlgorithm(Algorithm::Native), _ => Select::ByAlgorithm(Algorithm::Newton),
}
}
#[inline]
#[must_use]
pub(crate) fn dispatch<const N: usize, const SCALE: u32>(raw: Int<N>, mode: RoundingMode) -> Int<N>
where
Limbs<N>: ComputeLimbs,
{
if raw <= Int::<N>::ZERO {
return Int::<N>::ZERO;
}
let algo = match const { select::<N, SCALE>() } {
Select::ByAlgorithm(a) => a,
Select::ByValue(f) => f(&raw),
};
match algo {
Algorithm::Newton => sqrt::sqrt_newton::sqrt_newton::<N>(raw, SCALE, mode),
Algorithm::MgDivide => {
sqrt::sqrt_mg_divide::sqrt_mg_divide(raw.resize_to::<Int<2>>(), SCALE, mode)
.resize_to::<Int<N>>()
}
Algorithm::NewtonWithTableSeed => {
sqrt::sqrt_newton_with_table_seed::sqrt_newton_with_table_seed(
raw.resize_to::<Int<3>>(),
mode,
)
.resize_to::<Int<N>>()
}
Algorithm::Native => match N {
3 => sqrt::sqrt_native::sqrt_native::<N, 6>(raw, const { Int::<6>::TEN.pow(SCALE) }, mode),
4 => sqrt::sqrt_native::sqrt_native::<N, 8>(raw, const { Int::<8>::TEN.pow(SCALE) }, mode),
6 => sqrt::sqrt_native::sqrt_native::<N, 12>(raw, const { Int::<12>::TEN.pow(SCALE) }, mode),
8 => sqrt::sqrt_native::sqrt_native::<N, 16>(raw, const { Int::<16>::TEN.pow(SCALE) }, mode),
12 => sqrt::sqrt_native::sqrt_native::<N, 24>(raw, const { Int::<24>::TEN.pow(SCALE) }, mode),
16 => sqrt::sqrt_native::sqrt_native::<N, 32>(raw, const { Int::<32>::TEN.pow(SCALE) }, mode),
24 => sqrt::sqrt_native::sqrt_native::<N, 48>(raw, const { Int::<48>::TEN.pow(SCALE) }, mode),
32 => sqrt::sqrt_native::sqrt_native::<N, 64>(raw, const { Int::<64>::TEN.pow(SCALE) }, mode),
48 => sqrt::sqrt_native::sqrt_native::<N, 96>(raw, const { Int::<96>::TEN.pow(SCALE) }, mode),
64 => sqrt::sqrt_native::sqrt_native::<N, 128>(raw, const { Int::<128>::TEN.pow(SCALE) }, mode),
_ => sqrt::sqrt_newton::sqrt_newton::<N>(raw, SCALE, mode),
},
Algorithm::Schoolbook => sqrt::sqrt_newton::sqrt_newton::<N>(raw, SCALE, mode),
}
}