Make const

This commit is contained in:
Michael Pfaff 2022-03-01 18:30:30 -05:00
parent 2df2b3c365
commit 83649f11fa
Signed by: michael
GPG Key ID: F1A27427218FCA77
2 changed files with 45 additions and 17 deletions

View File

@ -2,7 +2,7 @@
name = "integer-sqrt" name = "integer-sqrt"
description = """ description = """
An implementation of integer square root algorithm for primitive rust types""" An implementation of integer square root algorithm for primitive rust types"""
version = "0.1.5" version = "0.2.0"
authors = ["Richard Dodd <richard.o.dodd@gmail.com>", "Joseph Richey", "Sergei Shulepov"] authors = ["Richard Dodd <richard.o.dodd@gmail.com>", "Joseph Richey", "Sergei Shulepov"]
include = ["src/**/*.rs", "Cargo.toml"] include = ["src/**/*.rs", "Cargo.toml"]
repository = "https://github.com/derekdreery/integer-sqrt-rs" repository = "https://github.com/derekdreery/integer-sqrt-rs"
@ -10,6 +10,7 @@ readme = "README.md"
keywords = ["integer", "square", "root", "isqrt", "sqrt"] keywords = ["integer", "square", "root", "isqrt", "sqrt"]
categories = ["algorithms", "no-std"] categories = ["algorithms", "no-std"]
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
edition = "2021"
[dependencies] [dependencies]
num-traits = { version = "0.2", default-features = false } static_assertions = "1.1"

View File

@ -16,6 +16,9 @@
//! //!
//! [`IntegerSquareRoot`]: ./trait.IntegerSquareRoot.html //! [`IntegerSquareRoot`]: ./trait.IntegerSquareRoot.html
#![no_std] #![no_std]
#![feature(const_trait_impl)]
#![feature(const_fn_trait_bound)]
#![feature(const_option)]
/// A trait implementing integer square root. /// A trait implementing integer square root.
pub trait IntegerSquareRoot { pub trait IntegerSquareRoot {
@ -29,6 +32,7 @@ pub trait IntegerSquareRoot {
/// For negative numbers (`i` family) this function will panic on negative input /// For negative numbers (`i` family) this function will panic on negative input
/// ///
/// [wiki_article]: https://en.wikipedia.org/wiki/Integer_square_root /// [wiki_article]: https://en.wikipedia.org/wiki/Integer_square_root
#[default_method_body_is_const]
fn integer_sqrt(&self) -> Self fn integer_sqrt(&self) -> Self
where where
Self: Sized, Self: Sized,
@ -44,39 +48,62 @@ pub trait IntegerSquareRoot {
Self: Sized; Self: Sized;
} }
impl<T: num_traits::PrimInt> IntegerSquareRoot for T { macro_rules! integer_sqrt {
fn integer_sqrt_checked(&self) -> Option<Self> { ($ty:ty as $unsigned_ty:ty, $value:expr) => {{
static_assertions::assert_eq_size!($ty, $unsigned_ty);
use core::cmp::Ordering; use core::cmp::Ordering;
match self.cmp(&T::zero()) { match $value {
0 => return Some(0),
// Hopefully this will be stripped for unsigned numbers (impossible condition) // Hopefully this will be stripped for unsigned numbers (impossible condition)
Ordering::Less => return None, v if v < 0 => return None,
Ordering::Equal => return Some(T::zero()),
_ => {} _ => {}
} }
// Compute bit, the largest power of 4 <= n // Compute bit, the largest power of 4 <= n
let max_shift: u32 = T::zero().leading_zeros() - 1; const ZERO: $ty = 0;
let shift: u32 = (max_shift - self.leading_zeros()) & !1; let max_shift: u32 = ZERO.leading_zeros() - 1;
let mut bit = T::one().unsigned_shl(shift); let shift: u32 = (max_shift - $value.leading_zeros()) & !1;
let mut bit = (1 as $unsigned_ty << shift) as $ty;
// Algorithm based on the implementation in: // Algorithm based on the implementation in:
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2) // 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). // Note that result/bit are logically unsigned (even if T is signed).
let mut n = *self; let mut n = $value;
let mut result = T::zero(); let mut result = 0;
while bit != T::zero() { while bit != 0 {
if n >= (result + bit) { if n >= (result + bit) {
n = n - (result + bit); n = n - (result + bit);
result = result.unsigned_shr(1) + bit; result = (result as $unsigned_ty >> 1) as $ty + bit;
} else { } else {
result = result.unsigned_shr(1); result = (result as $unsigned_ty >> 1) as $ty;
} }
bit = bit.unsigned_shr(2); bit = (bit as $unsigned_ty >> 2) as $ty;
} }
Some(result) Some(result)
} }};
(impl const $ty:ty as $unsigned_ty:ty) => {
impl const IntegerSquareRoot for $ty {
fn integer_sqrt_checked(&self) -> Option<Self> {
integer_sqrt!($ty as $unsigned_ty, *self)
}
}
};
} }
integer_sqrt!(impl const u8 as u8);
integer_sqrt!(impl const u16 as u16);
integer_sqrt!(impl const u32 as u32);
integer_sqrt!(impl const u64 as u64);
integer_sqrt!(impl const u128 as u128);
integer_sqrt!(impl const usize as usize);
integer_sqrt!(impl const i8 as u8);
integer_sqrt!(impl const i16 as u16);
integer_sqrt!(impl const i32 as u32);
integer_sqrt!(impl const i64 as u64);
integer_sqrt!(impl const i128 as u128);
integer_sqrt!(impl const isize as usize);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::IntegerSquareRoot; use super::IntegerSquareRoot;