Skip to main content

const_num_traits/ops/
sqrt.rs

1//! Integer square root, mirroring the `isqrt` / `checked_isqrt` inherent
2//! methods (stable in std since Rust 1.84).
3//!
4//! Split: `checked_isqrt` exists in std only on signed types
5//! (it can't fail for unsigned ones), so it lives in its own signed-only
6//! trait rather than forcing an artificial always-`Some` method onto the
7//! unsigned impls.
8//!
9//! **CT tier C (CT-hostile)**: integer square root is an iterative,
10//! data-dependent computation.
11
12c0nst::c0nst! {
13/// Integer square root.
14pub c0nst trait Isqrt: Sized {
15    /// Returns the integer square root: the largest integer `r` such that
16    /// `r * r <= self`.
17    ///
18    /// # Panics
19    ///
20    /// Panics if `self` is negative (signed types only).
21    ///
22    /// ```
23    /// use const_num_traits::Isqrt;
24    ///
25    /// assert_eq!(Isqrt::isqrt(10u32), 3);
26    /// assert_eq!(Isqrt::isqrt(16u32), 4);
27    /// ```
28    type Output;
29    fn isqrt(self) -> Self::Output;
30}
31}
32
33c0nst::c0nst! {
34/// Integer square root of signed values, `None` for negative inputs.
35pub c0nst trait CheckedIsqrt: Sized {
36    /// Returns the integer square root, or `None` if `self` is negative.
37    /// Like std, this is only provided for signed types.
38    ///
39    /// ```
40    /// use const_num_traits::CheckedIsqrt;
41    ///
42    /// assert_eq!(CheckedIsqrt::checked_isqrt(10i32), Some(3));
43    /// assert_eq!(CheckedIsqrt::checked_isqrt(-1i32), None);
44    /// ```
45    type Output;
46    fn checked_isqrt(self) -> Option<Self::Output>;
47}
48}
49
50macro_rules! isqrt_impl {
51    ($($t:ty)*) => {$(
52        c0nst::c0nst! {
53        c0nst impl Isqrt for $t {
54            type Output = $t;
55            #[inline]
56            fn isqrt(self) -> Self {
57                <$t>::isqrt(self)
58            }
59        }
60        }
61    )*};
62}
63
64macro_rules! checked_isqrt_impl {
65    ($($t:ty)*) => {$(
66        c0nst::c0nst! {
67        c0nst impl CheckedIsqrt for $t {
68            type Output = $t;
69            #[inline]
70            fn checked_isqrt(self) -> Option<Self> {
71                <$t>::checked_isqrt(self)
72            }
73        }
74        }
75    )*};
76}
77
78isqrt_impl!(usize u8 u16 u32 u64 u128);
79isqrt_impl!(isize i8 i16 i32 i64 i128);
80checked_isqrt_impl!(isize i8 i16 i32 i64 i128);
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn isqrt() {
88        assert_eq!(Isqrt::isqrt(0u8), 0);
89        assert_eq!(Isqrt::isqrt(u128::MAX), (1u128 << 64) - 1);
90        assert_eq!(Isqrt::isqrt(99i32), 9);
91        assert_eq!(Isqrt::isqrt(100i32), 10);
92        assert_eq!(CheckedIsqrt::checked_isqrt(-1i32), None);
93        assert_eq!(CheckedIsqrt::checked_isqrt(255i32), Some(15));
94    }
95}