Skip to content

Commit 727a4fc

Browse files
committed
Implement #88581
1 parent 76e755c commit 727a4fc

File tree

5 files changed

+346
-0
lines changed

5 files changed

+346
-0
lines changed

library/core/src/num/int_macros.rs

+167
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,173 @@ macro_rules! int_impl {
17461746
}
17471747
}
17481748

1749+
/// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
1750+
///
1751+
/// # Panics
1752+
///
1753+
/// This function will panic if `rhs` is 0 or the division results in overflow.
1754+
///
1755+
/// # Examples
1756+
///
1757+
/// Basic usage:
1758+
///
1759+
/// ```
1760+
/// #![feature(int_roundings)]
1761+
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
1762+
/// let b = 3;
1763+
///
1764+
/// assert_eq!(a.div_floor(b), 2);
1765+
/// assert_eq!(a.div_floor(-b), -3);
1766+
/// assert_eq!((-a).div_floor(b), -3);
1767+
/// assert_eq!((-a).div_floor(-b), 2);
1768+
/// ```
1769+
#[unstable(feature = "int_roundings", issue = "88581")]
1770+
#[must_use = "this returns the result of the operation, \
1771+
without modifying the original"]
1772+
#[inline]
1773+
#[rustc_inherit_overflow_checks]
1774+
pub const fn div_floor(self, rhs: Self) -> Self {
1775+
let d = self / rhs;
1776+
let r = self % rhs;
1777+
if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
1778+
d - 1
1779+
} else {
1780+
d
1781+
}
1782+
}
1783+
1784+
/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
1785+
///
1786+
/// # Panics
1787+
///
1788+
/// This function will panic if `rhs` is 0 or the division results in overflow.
1789+
///
1790+
/// # Examples
1791+
///
1792+
/// Basic usage:
1793+
///
1794+
/// ```
1795+
/// #![feature(int_roundings)]
1796+
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
1797+
/// let b = 3;
1798+
///
1799+
/// assert_eq!(a.div_ceil(b), 3);
1800+
/// assert_eq!(a.div_ceil(-b), -2);
1801+
/// assert_eq!((-a).div_ceil(b), -2);
1802+
/// assert_eq!((-a).div_ceil(-b), 3);
1803+
/// ```
1804+
#[unstable(feature = "int_roundings", issue = "88581")]
1805+
#[must_use = "this returns the result of the operation, \
1806+
without modifying the original"]
1807+
#[inline]
1808+
#[rustc_inherit_overflow_checks]
1809+
pub const fn div_ceil(self, rhs: Self) -> Self {
1810+
let d = self / rhs;
1811+
let r = self % rhs;
1812+
if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
1813+
d + 1
1814+
} else {
1815+
d
1816+
}
1817+
}
1818+
1819+
/// If `rhs` is positive, calculates the smallest value greater than or
1820+
/// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
1821+
/// calculates the largest value less than or equal to `self` that is a
1822+
/// multiple of `rhs`.
1823+
///
1824+
/// # Panics
1825+
///
1826+
/// This function will panic if `rhs` is 0 or the operation results in overflow.
1827+
///
1828+
/// # Examples
1829+
///
1830+
/// Basic usage:
1831+
///
1832+
/// ```
1833+
/// #![feature(int_roundings)]
1834+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
1835+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
1836+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
1837+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
1838+
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
1839+
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
1840+
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")]
1841+
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")]
1842+
/// ```
1843+
#[unstable(feature = "int_roundings", issue = "88581")]
1844+
#[must_use = "this returns the result of the operation, \
1845+
without modifying the original"]
1846+
#[inline]
1847+
#[rustc_inherit_overflow_checks]
1848+
pub const fn next_multiple_of(self, rhs: Self) -> Self {
1849+
// This would otherwise fail when calculating `r` when self == T::MIN.
1850+
if rhs == -1 {
1851+
return self;
1852+
}
1853+
1854+
let r = self % rhs;
1855+
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
1856+
r + rhs
1857+
} else {
1858+
r
1859+
};
1860+
1861+
if m == 0 {
1862+
self
1863+
} else {
1864+
self + (rhs - m)
1865+
}
1866+
}
1867+
1868+
/// If `rhs` is positive, calculates the smallest value greater than or
1869+
/// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
1870+
/// calculates the largest value less than or equal to `self` that is a
1871+
/// multiple of `rhs`. Returns `None` if `rhs` is zero or the operation
1872+
/// would result in overflow.
1873+
///
1874+
/// # Examples
1875+
///
1876+
/// Basic usage:
1877+
///
1878+
/// ```
1879+
/// #![feature(int_roundings)]
1880+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
1881+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
1882+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
1883+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
1884+
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
1885+
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
1886+
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-16));")]
1887+
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-24));")]
1888+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
1889+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
1890+
/// ```
1891+
#[unstable(feature = "int_roundings", issue = "88581")]
1892+
#[must_use = "this returns the result of the operation, \
1893+
without modifying the original"]
1894+
#[inline]
1895+
#[rustc_inherit_overflow_checks]
1896+
pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1897+
// This would otherwise fail when calculating `r` when self == T::MIN.
1898+
if rhs == -1 {
1899+
return Some(self);
1900+
}
1901+
1902+
let r = try_opt!(self.checked_rem(rhs));
1903+
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
1904+
try_opt!(r.checked_add(rhs))
1905+
} else {
1906+
r
1907+
};
1908+
1909+
if m == 0 {
1910+
Some(self)
1911+
} else {
1912+
self.checked_add(try_opt!(rhs.checked_sub(m)))
1913+
}
1914+
}
1915+
17491916
/// Returns the logarithm of the number with respect to an arbitrary base.
17501917
///
17511918
/// This method might not be optimized owing to implementation details;

library/core/src/num/uint_macros.rs

+104
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,110 @@ macro_rules! uint_impl {
17581758
self % rhs
17591759
}
17601760

1761+
/// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
1762+
///
1763+
/// This is the same as performing `self / rhs` for all unsigned integers.
1764+
///
1765+
/// # Panics
1766+
///
1767+
/// This function will panic if `rhs` is 0.
1768+
///
1769+
/// # Examples
1770+
///
1771+
/// Basic usage:
1772+
///
1773+
/// ```
1774+
/// #![feature(int_roundings)]
1775+
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")]
1776+
/// ```
1777+
#[unstable(feature = "int_roundings", issue = "88581")]
1778+
#[inline(always)]
1779+
#[rustc_inherit_overflow_checks]
1780+
pub const fn div_floor(self, rhs: Self) -> Self {
1781+
self / rhs
1782+
}
1783+
1784+
/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
1785+
///
1786+
/// # Panics
1787+
///
1788+
/// This function will panic if `rhs` is 0.
1789+
///
1790+
/// # Examples
1791+
///
1792+
/// Basic usage:
1793+
///
1794+
/// ```
1795+
/// #![feature(int_roundings)]
1796+
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")]
1797+
/// ```
1798+
#[unstable(feature = "int_roundings", issue = "88581")]
1799+
#[inline]
1800+
#[rustc_inherit_overflow_checks]
1801+
pub const fn div_ceil(self, rhs: Self) -> Self {
1802+
let d = self / rhs;
1803+
let r = self % rhs;
1804+
if r > 0 && rhs > 0 {
1805+
d + 1
1806+
} else {
1807+
d
1808+
}
1809+
}
1810+
1811+
/// Calculates the smallest value greater than or equal to `self` that
1812+
/// is a multiple of `rhs`.
1813+
///
1814+
/// # Panics
1815+
///
1816+
/// This function will panic if `rhs` is 0 or the operation results in overflow.
1817+
///
1818+
/// # Examples
1819+
///
1820+
/// Basic usage:
1821+
///
1822+
/// ```
1823+
/// #![feature(int_roundings)]
1824+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
1825+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
1826+
/// ```
1827+
#[unstable(feature = "int_roundings", issue = "88581")]
1828+
#[must_use = "this returns the result of the operation, \
1829+
without modifying the original"]
1830+
#[inline]
1831+
#[rustc_inherit_overflow_checks]
1832+
pub const fn next_multiple_of(self, rhs: Self) -> Self {
1833+
match self % rhs {
1834+
0 => self,
1835+
r => self + (rhs - r)
1836+
}
1837+
}
1838+
1839+
/// Calculates the smallest value greater than or equal to `self` that
1840+
/// is a multiple of `rhs`. If `rhs` is negative,
1841+
///
1842+
/// # Examples
1843+
///
1844+
/// Basic usage:
1845+
///
1846+
/// ```
1847+
/// #![feature(int_roundings)]
1848+
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
1849+
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
1850+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
1851+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
1852+
/// ```
1853+
#[unstable(feature = "int_roundings", issue = "88581")]
1854+
#[must_use = "this returns the result of the operation, \
1855+
without modifying the original"]
1856+
#[inline]
1857+
#[rustc_inherit_overflow_checks]
1858+
pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1859+
match try_opt!(self.checked_rem(rhs)) {
1860+
0 => Some(self),
1861+
r => self.checked_add(try_opt!(rhs.checked_sub(r)))
1862+
}
1863+
}
1864+
17611865
/// Returns `true` if and only if `self == 2^k` for some `k`.
17621866
///
17631867
/// # Examples

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#![feature(unsized_tuple_coercion)]
6666
#![feature(const_option)]
6767
#![feature(integer_atomics)]
68+
#![feature(int_roundings)]
6869
#![feature(slice_group_by)]
6970
#![feature(trusted_random_access)]
7071
#![feature(unsize)]

library/core/tests/num/int_macros.rs

+49
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,55 @@ macro_rules! int_module {
289289
assert_eq!(r.saturating_pow(3), -8 as $T);
290290
assert_eq!(r.saturating_pow(0), 1 as $T);
291291
}
292+
293+
#[test]
294+
fn test_div_floor() {
295+
let a: $T = 8;
296+
let b = 3;
297+
assert_eq!(a.div_floor(b), 2);
298+
assert_eq!(a.div_floor(-b), -3);
299+
assert_eq!((-a).div_floor(b), -3);
300+
assert_eq!((-a).div_floor(-b), 2);
301+
}
302+
303+
#[test]
304+
fn test_div_ceil() {
305+
let a: $T = 8;
306+
let b = 3;
307+
assert_eq!(a.div_ceil(b), 3);
308+
assert_eq!(a.div_ceil(-b), -2);
309+
assert_eq!((-a).div_ceil(b), -2);
310+
assert_eq!((-a).div_ceil(-b), 3);
311+
}
312+
313+
#[test]
314+
fn test_next_multiple_of() {
315+
assert_eq!((16 as $T).next_multiple_of(8), 16);
316+
assert_eq!((23 as $T).next_multiple_of(8), 24);
317+
assert_eq!((16 as $T).next_multiple_of(-8), 16);
318+
assert_eq!((23 as $T).next_multiple_of(-8), 16);
319+
assert_eq!((-16 as $T).next_multiple_of(8), -16);
320+
assert_eq!((-23 as $T).next_multiple_of(8), -16);
321+
assert_eq!((-16 as $T).next_multiple_of(-8), -16);
322+
assert_eq!((-23 as $T).next_multiple_of(-8), -24);
323+
assert_eq!(MIN.next_multiple_of(-1), MIN);
324+
}
325+
326+
#[test]
327+
fn test_checked_next_multiple_of() {
328+
assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
329+
assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
330+
assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16));
331+
assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16));
332+
assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16));
333+
assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16));
334+
assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
335+
assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
336+
assert_eq!((1 as $T).checked_next_multiple_of(0), None);
337+
assert_eq!(MAX.checked_next_multiple_of(2), None);
338+
assert_eq!(MIN.checked_next_multiple_of(-3), None);
339+
assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
340+
}
292341
}
293342
};
294343
}

library/core/tests/num/uint_macros.rs

+25
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,31 @@ macro_rules! uint_module {
205205
assert_eq!(r.overflowing_pow(2), (1 as $T, true));
206206
assert_eq!(r.saturating_pow(2), MAX);
207207
}
208+
209+
#[test]
210+
fn test_div_floor() {
211+
assert_eq!((8 as $T).div_floor(3), 2);
212+
}
213+
214+
#[test]
215+
fn test_div_ceil() {
216+
assert_eq!((8 as $T).div_ceil(3), 3);
217+
}
218+
219+
#[test]
220+
fn test_next_multiple_of() {
221+
assert_eq!((16 as $T).next_multiple_of(8), 16);
222+
assert_eq!((23 as $T).next_multiple_of(8), 24);
223+
assert_eq!(MAX.next_multiple_of(1), MAX);
224+
}
225+
226+
#[test]
227+
fn test_checked_next_multiple_of() {
228+
assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
229+
assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
230+
assert_eq!((1 as $T).checked_next_multiple_of(0), None);
231+
assert_eq!(MAX.checked_next_multiple_of(2), None);
232+
}
208233
}
209234
};
210235
}

0 commit comments

Comments
 (0)