Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9f20a0f

Browse files
authoredJul 19, 2024
Rollup merge of rust-lang#126199 - ivan-shrimp:nonzero_isqrt, r=tgross35
Add `isqrt` to `NonZero<uN>` Implements [rust-lang#70887 (comment)](rust-lang#116226 (comment)), with the following signature: ```rust impl NonZero<uN> { const fn isqrt(self) -> Self; } ``` Unintended benefits include one fewer panicking branch in `ilog2` for LLVM to optimize away, and one fewer `assume_unchecked` as `NonZero` already does that. The fast path for `self == 1` is dropped, but the current implementation is very slow anyways compared to hardware. Performance improvements can always come later. (I didn't add the function to `NonZero<iN>`, since _every_ existing `NonZero` method is non-panicking, and it might be nice to leave it that way.)
2 parents f06530c + f3b1c8a commit 9f20a0f

File tree

3 files changed

+63
-45
lines changed

3 files changed

+63
-45
lines changed
 

‎core/src/num/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#![stable(feature = "rust1", since = "1.0.0")]
44

55
use crate::ascii;
6-
use crate::hint;
76
use crate::intrinsics;
87
use crate::mem;
98
use crate::str::FromStr;

‎core/src/num/nonzero.rs

+54-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::cmp::Ordering;
44
use crate::fmt;
55
use crate::hash::{Hash, Hasher};
6+
use crate::hint;
67
use crate::intrinsics;
78
use crate::marker::{Freeze, StructuralPartialEq};
89
use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
@@ -604,7 +605,6 @@ macro_rules! nonzero_integer {
604605
}
605606

606607
nonzero_integer_signedness_dependent_methods! {
607-
Self = $Ty,
608608
Primitive = $signedness $Int,
609609
UnsignedPrimitive = $Uint,
610610
}
@@ -823,7 +823,7 @@ macro_rules! nonzero_integer {
823823
}
824824
}
825825

826-
nonzero_integer_signedness_dependent_impls!($Ty $signedness $Int);
826+
nonzero_integer_signedness_dependent_impls!($signedness $Int);
827827
};
828828

829829
(Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => {
@@ -849,7 +849,7 @@ macro_rules! nonzero_integer {
849849

850850
macro_rules! nonzero_integer_signedness_dependent_impls {
851851
// Impls for unsigned nonzero types only.
852-
($Ty:ident unsigned $Int:ty) => {
852+
(unsigned $Int:ty) => {
853853
#[stable(feature = "nonzero_div", since = "1.51.0")]
854854
impl Div<NonZero<$Int>> for $Int {
855855
type Output = $Int;
@@ -897,7 +897,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
897897
}
898898
};
899899
// Impls for signed nonzero types only.
900-
($Ty:ident signed $Int:ty) => {
900+
(signed $Int:ty) => {
901901
#[stable(feature = "signed_nonzero_neg", since = "1.71.0")]
902902
impl Neg for NonZero<$Int> {
903903
type Output = Self;
@@ -918,7 +918,6 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
918918
macro_rules! nonzero_integer_signedness_dependent_methods {
919919
// Associated items for unsigned nonzero types only.
920920
(
921-
Self = $Ty:ident,
922921
Primitive = unsigned $Int:ident,
923922
UnsignedPrimitive = $Uint:ty,
924923
) => {
@@ -1224,11 +1223,60 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
12241223

12251224
intrinsics::ctpop(self.get()) < 2
12261225
}
1226+
1227+
/// Returns the square root of the number, rounded down.
1228+
///
1229+
/// # Examples
1230+
///
1231+
/// Basic usage:
1232+
/// ```
1233+
/// #![feature(isqrt)]
1234+
/// # use std::num::NonZero;
1235+
/// #
1236+
/// # fn main() { test().unwrap(); }
1237+
/// # fn test() -> Option<()> {
1238+
#[doc = concat!("let ten = NonZero::new(10", stringify!($Int), ")?;")]
1239+
#[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")]
1240+
///
1241+
/// assert_eq!(ten.isqrt(), three);
1242+
/// # Some(())
1243+
/// # }
1244+
#[unstable(feature = "isqrt", issue = "116226")]
1245+
#[rustc_const_unstable(feature = "isqrt", issue = "116226")]
1246+
#[must_use = "this returns the result of the operation, \
1247+
without modifying the original"]
1248+
#[inline]
1249+
pub const fn isqrt(self) -> Self {
1250+
// The algorithm is based on the one presented in
1251+
// <https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)>
1252+
// which cites as source the following C code:
1253+
// <https://web.archive.org/web/20120306040058/http://medialab.freaknet.org/martin/src/sqrt/sqrt.c>.
1254+
1255+
let mut op = self.get();
1256+
let mut res = 0;
1257+
let mut one = 1 << (self.ilog2() & !1);
1258+
1259+
while one != 0 {
1260+
if op >= res + one {
1261+
op -= res + one;
1262+
res = (res >> 1) + one;
1263+
} else {
1264+
res >>= 1;
1265+
}
1266+
one >>= 2;
1267+
}
1268+
1269+
// SAFETY: The result fits in an integer with half as many bits.
1270+
// Inform the optimizer about it.
1271+
unsafe { hint::assert_unchecked(res < 1 << (Self::BITS / 2)) };
1272+
1273+
// SAFETY: The square root of an integer >= 1 is always >= 1.
1274+
unsafe { Self::new_unchecked(res) }
1275+
}
12271276
};
12281277

12291278
// Associated items for signed nonzero types only.
12301279
(
1231-
Self = $Ty:ident,
12321280
Primitive = signed $Int:ident,
12331281
UnsignedPrimitive = $Uint:ty,
12341282
) => {

‎core/src/num/uint_macros.rs

+9-38
Original file line numberDiff line numberDiff line change
@@ -1226,10 +1226,9 @@ macro_rules! uint_impl {
12261226
without modifying the original"]
12271227
#[inline]
12281228
pub const fn checked_ilog2(self) -> Option<u32> {
1229-
if let Some(x) = NonZero::new(self) {
1230-
Some(x.ilog2())
1231-
} else {
1232-
None
1229+
match NonZero::new(self) {
1230+
Some(x) => Some(x.ilog2()),
1231+
None => None,
12331232
}
12341233
}
12351234

@@ -1248,10 +1247,9 @@ macro_rules! uint_impl {
12481247
without modifying the original"]
12491248
#[inline]
12501249
pub const fn checked_ilog10(self) -> Option<u32> {
1251-
if let Some(x) = NonZero::new(self) {
1252-
Some(x.ilog10())
1253-
} else {
1254-
None
1250+
match NonZero::new(self) {
1251+
Some(x) => Some(x.ilog10()),
1252+
None => None,
12551253
}
12561254
}
12571255

@@ -2590,37 +2588,10 @@ macro_rules! uint_impl {
25902588
without modifying the original"]
25912589
#[inline]
25922590
pub const fn isqrt(self) -> Self {
2593-
if self < 2 {
2594-
return self;
2595-
}
2596-
2597-
// The algorithm is based on the one presented in
2598-
// <https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)>
2599-
// which cites as source the following C code:
2600-
// <https://web.archive.org/web/20120306040058/http://medialab.freaknet.org/martin/src/sqrt/sqrt.c>.
2601-
2602-
let mut op = self;
2603-
let mut res = 0;
2604-
let mut one = 1 << (self.ilog2() & !1);
2605-
2606-
while one != 0 {
2607-
if op >= res + one {
2608-
op -= res + one;
2609-
res = (res >> 1) + one;
2610-
} else {
2611-
res >>= 1;
2612-
}
2613-
one >>= 2;
2591+
match NonZero::new(self) {
2592+
Some(x) => x.isqrt().get(),
2593+
None => 0,
26142594
}
2615-
2616-
// SAFETY: the result is positive and fits in an integer with half as many bits.
2617-
// Inform the optimizer about it.
2618-
unsafe {
2619-
hint::assert_unchecked(0 < res);
2620-
hint::assert_unchecked(res < 1 << (Self::BITS / 2));
2621-
}
2622-
2623-
res
26242595
}
26252596

26262597
/// Performs Euclidean division.

0 commit comments

Comments
 (0)
Failed to load comments.