Make const
This commit is contained in:
parent
2df2b3c365
commit
83649f11fa
|
@ -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"
|
||||||
|
|
57
src/lib.rs
57
src/lib.rs
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue