Skip to main content

nekolib/math/
sqrt.rs

1//! 平方根。
2
3/// 平方根。
4///
5/// $\\lfloor\\sqrt{n}\\rfloor$ を求める。
6///
7/// # Complexity
8/// $O(\\log(n))$ time.
9///
10/// Newton 法で $O(\\log(\\log(n)))$ time にするべき?
11///
12/// # Examples
13/// ```
14/// use nekolib::math::Sqrt;
15///
16/// assert_eq!(0_i32.sqrt(), 0);
17/// assert_eq!(9_i32.sqrt(), 3);
18/// assert_eq!(12_i32.sqrt(), 3);
19/// assert_eq!(16_i32.sqrt(), 4);
20///
21/// assert_eq!(u128::MAX.sqrt(), (1 << 64) - 1);
22/// ```
23///
24/// ```should_panic
25/// use nekolib::math::Sqrt;
26///
27/// (-1_i32).sqrt();
28/// ```
29pub trait Sqrt {
30    fn sqrt(self) -> Self;
31}
32
33macro_rules! impl_uint {
34    ($t:ty) => {
35        impl Sqrt for $t {
36            fn sqrt(self) -> Self {
37                let pred = |i: $t| {
38                    i.checked_pow(2).map(|i2| i2 <= self).unwrap_or(false)
39                };
40                let mut ok = 0;
41                let mut bad = 1;
42                while pred(bad) {
43                    bad *= 2;
44                }
45                while bad - ok > 1 {
46                    let mid = ok + (bad - ok) / 2;
47                    *(if pred(mid) { &mut ok } else { &mut bad }) = mid;
48                }
49                ok
50            }
51        }
52    };
53    ( $($t:ty)* ) => { $(impl_uint!($t);)* };
54}
55
56macro_rules! impl_int {
57    ($t:ty) => {
58        impl Sqrt for $t {
59            fn sqrt(self) -> Self {
60                assert!(self >= 0, "must be non-negative");
61                let pred = |i: $t| {
62                    i.checked_pow(2).map(|i2| i2 <= self).unwrap_or(false)
63                };
64                let mut ok = 0;
65                let mut bad = 1;
66                while pred(bad) {
67                    bad *= 2;
68                }
69                while bad - ok > 1 {
70                    let mid = ok + (bad - ok) / 2;
71                    *(if pred(mid) { &mut ok } else { &mut bad }) = mid;
72                }
73                ok
74            }
75        }
76    };
77    ( $($t:ty)* ) => { $(impl_int!($t);)* };
78}
79
80impl_uint!(u8 u16 u32 u64 u128 usize);
81impl_int!(i8 i16 i32 i64 i128 isize);