From 6b4ff514d99511354ed206c2544b821b6986bf78 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Thu, 5 Sep 2024 22:50:41 +0200 Subject: [PATCH] better implementation of signed div_floor/ceil --- library/core/src/num/int_macros.rs | 20 ++++++++++++++++---- 1 file 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 }