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