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}