Remove impl_isqrt macro
The implementation can now just use a normal generic impl. Note that this is tecnically a minor breaking change, as if a user has both: - A custom num_traits::PrimInt impl - A custom IntegerSquareRoot impl Their code will no longer compile Signed-off-by: Joe Richey <joerichey@google.com>
This commit is contained in:
parent
e0a70c1472
commit
e620eeed5e
64
src/lib.rs
64
src/lib.rs
|
@ -44,49 +44,39 @@ pub trait IntegerSquareRoot {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
impl<T: num_traits::PrimInt> IntegerSquareRoot for T {
|
||||||
fn integer_sqrt_impl<T: num_traits::PrimInt>(mut n: T) -> Option<T> {
|
fn integer_sqrt_checked(&self) -> Option<Self> {
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
match n.cmp(&T::zero()) {
|
match self.cmp(&T::zero()) {
|
||||||
// Hopefully this will be stripped for unsigned numbers (impossible condition)
|
// Hopefully this will be stripped for unsigned numbers (impossible condition)
|
||||||
Ordering::Less => return None,
|
Ordering::Less => return None,
|
||||||
Ordering::Equal => return Some(T::zero()),
|
Ordering::Equal => return Some(T::zero()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
|
||||||
|
|
||||||
// Compute bit, the largest power of 4 <= n
|
|
||||||
let max_shift: u32 = T::zero().leading_zeros() - 1;
|
|
||||||
let shift: u32 = (max_shift - n.leading_zeros()) & !1;
|
|
||||||
let mut bit = T::one().unsigned_shl(shift);
|
|
||||||
|
|
||||||
// Algorithm based on the implementation in:
|
|
||||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)
|
|
||||||
// Note that result/bit are logically unsigned (even if T is signed).
|
|
||||||
let mut result = T::zero();
|
|
||||||
while bit != T::zero() {
|
|
||||||
if n >= (result + bit) {
|
|
||||||
n = n - (result + bit);
|
|
||||||
result = result.unsigned_shr(1) + bit;
|
|
||||||
} else {
|
|
||||||
result = result.unsigned_shr(1);
|
|
||||||
}
|
}
|
||||||
bit = bit.unsigned_shr(2);
|
|
||||||
}
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_isqrt {
|
// Compute bit, the largest power of 4 <= n
|
||||||
($($t:ty)*) => { $(
|
let max_shift: u32 = T::zero().leading_zeros() - 1;
|
||||||
impl IntegerSquareRoot for $t {
|
let shift: u32 = (max_shift - self.leading_zeros()) & !1;
|
||||||
fn integer_sqrt_checked(&self) -> Option<Self> {
|
let mut bit = T::one().unsigned_shl(shift);
|
||||||
integer_sqrt_impl(*self)
|
|
||||||
|
// Algorithm based on the implementation in:
|
||||||
|
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)
|
||||||
|
// Note that result/bit are logically unsigned (even if T is signed).
|
||||||
|
let mut n = *self;
|
||||||
|
let mut result = T::zero();
|
||||||
|
while bit != T::zero() {
|
||||||
|
if n >= (result + bit) {
|
||||||
|
n = n - (result + bit);
|
||||||
|
result = result.unsigned_shr(1) + bit;
|
||||||
|
} else {
|
||||||
|
result = result.unsigned_shr(1);
|
||||||
}
|
}
|
||||||
|
bit = bit.unsigned_shr(2);
|
||||||
}
|
}
|
||||||
)* };
|
Some(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_isqrt!(usize u128 u64 u32 u16 u8 isize i128 i64 i32 i16 i8);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::IntegerSquareRoot;
|
use super::IntegerSquareRoot;
|
||||||
|
|
Loading…
Reference in New Issue