about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOrson Peters <orsonpeters@gmail.com>2024-09-05 22:50:41 +0200
committerOrson Peters <orsonpeters@gmail.com>2024-09-05 22:50:41 +0200
commit6b4ff514d99511354ed206c2544b821b6986bf78 (patch)
tree5f9fff3d83a9e4e5010b6beee3812c9fec39c6d4
parenteb33b43bab08223fa6b46abacc1e95e859fe375d (diff)
downloadrust-6b4ff514d99511354ed206c2544b821b6986bf78.tar.gz
rust-6b4ff514d99511354ed206c2544b821b6986bf78.zip
better implementation of signed div_floor/ceil
-rw-r--r--library/core/src/num/int_macros.rs20
1 files changed, 16 insertions, 4 deletions
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 878a911dde5..7241b3ff6a3 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -3023,8 +3023,16 @@ macro_rules! int_impl {
         pub const fn div_floor(self, rhs: Self) -> Self {
             let d = self / rhs;
             let r = self % rhs;
-            if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
-                d - 1
+
+            // If the remainder is non-zero, we need to subtract one if the
+            // signs of self and rhs differ, as this means we rounded upwards
+            // instead of downwards. We do this branchlessly by creating a mask
+            // which is all-ones iff the signs differ, and 0 otherwise. Then by
+            // adding this mask (which corresponds to the signed value -1), we
+            // get our correction.
+            let correction = (self ^ rhs) >> (Self::BITS - 1);
+            if r != 0 {
+                d + correction
             } else {
                 d
             }
@@ -3059,8 +3067,12 @@ macro_rules! int_impl {
         pub const fn div_ceil(self, rhs: Self) -> Self {
             let d = self / rhs;
             let r = self % rhs;
-            if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
-                d + 1
+
+            // When remainder is non-zero we have a.div_ceil(b) == 1 + a.div_floor(b),
+            // so we can re-use the algorithm from div_floor, just adding 1.
+            let correction = 1 + ((self ^ rhs) >> (Self::BITS - 1));
+            if r != 0 {
+                d + correction
             } else {
                 d
             }