Skip to content

Commit 91e6918

Browse files
authored
Implement next_multiple_of() and is_multiple_of() (#83)
* Also adds `prev_multiple_of()`
1 parent 3a1f1de commit 91e6918

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

arbi/src/add.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,22 @@ impl Arbi {
9393
if self.is_negative() {
9494
if y_is_neg {
9595
// x < 0, y < 0 ==> x = -|x|, y = -|y| ==> x - y = |y| - |x|
96+
// y - x = -|y| - (-|x|) = |x| - |y|
9697
self.dsub_abs_inplace(y, !from_other);
9798
} else {
9899
// x < 0, y >= 0 ==> x = -|x|, y = |y| ==> x - y = -(|x| + |y|)
100+
// y - x = |y| + |x|
99101
self.dadd_abs_inplace(y);
100-
self.neg = true;
102+
self.neg = !from_other;
101103
}
102104
} else if y_is_neg {
103105
// x >= 0, y < 0 ==> x = |x|, y = -|y| ==> x - y = |x| + |y|
106+
// y - x = -|y| - |x| = -(|y| + |x|)
104107
self.dadd_abs_inplace(y);
108+
self.neg = from_other;
105109
} else {
106110
// x >= 0, y >= 0 ==> x = |x|, y = |y| ==> x - y = |x| - |y|
111+
// y - x = |y| - |x|
107112
self.dsub_abs_inplace(y, from_other);
108113
}
109114
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2025 Owain Davies
3+
SPDX-License-Identifier: Apache-2.0 OR MIT
4+
*/
5+
6+
use crate::Arbi;
7+
8+
impl Arbi {
9+
/// Returns `true` if `self` is an integer multiple of `rhs`, and `false`
10+
/// otherwise.
11+
///
12+
/// If both `self` and `rhs` are zero, returns `true`. If `self` is nonzero
13+
/// and `rhs` is zero, returns `false`. Otherwise, this function is
14+
/// equivalent to `self % rhs == 0`.
15+
///
16+
/// # Examples
17+
/// ```
18+
/// use arbi::Arbi;
19+
/// assert!(Arbi::from(8).is_multiple_of(&Arbi::from(4)));
20+
/// assert!(!Arbi::from(7).is_multiple_of(&Arbi::from(4)));
21+
/// assert!(Arbi::from(0).is_multiple_of(&Arbi::from(0)));
22+
/// assert!(!Arbi::from(7).is_multiple_of(&Arbi::from(0)));
23+
/// ```
24+
pub fn is_multiple_of(&self, rhs: &Self) -> bool {
25+
if rhs.is_zero() {
26+
self.is_zero()
27+
} else {
28+
(self % rhs).is_zero()
29+
}
30+
}
31+
}

arbi/src/builtin_int_methods/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ mod from_bytes;
1414
mod ilog;
1515
mod ilog10;
1616
mod ilog2;
17+
mod is_multiple_of;
1718
mod is_positive_is_negative;
1819
mod is_power_of_two;
1920
mod isqrt;
21+
mod next_multiple_of;
2022
mod reverse_bits;
2123
mod signum;
2224
mod swap_bytes;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Copyright 2025 Owain Davies
3+
SPDX-License-Identifier: Apache-2.0 OR MIT
4+
*/
5+
6+
use crate::{Arbi, Assign};
7+
8+
impl Arbi {
9+
/// If `rhs` is positive, return the smallest value greater than or equal to
10+
/// `self` that is a multiple of `rhs`. If `rhs` is negative, return the
11+
/// largest value less than or equal to `self` that is a multiple of `rhs`.
12+
///
13+
/// # Panic
14+
/// Panics if `rhs` is zero.
15+
///
16+
/// # Examples
17+
/// ```
18+
/// use arbi::Arbi;
19+
/// assert_eq!(Arbi::from(12).next_multiple_of(&Arbi::from(6)), 12);
20+
/// assert_eq!(Arbi::from(19).next_multiple_of(&Arbi::from(7)), 21);
21+
/// assert_eq!(Arbi::from(25).next_multiple_of(&Arbi::from(-5)), 25);
22+
/// assert_eq!(Arbi::from(25).next_multiple_of(&Arbi::from(-7)), 21);
23+
/// assert_eq!(Arbi::from(-21).next_multiple_of(&Arbi::from(7)), -21);
24+
/// assert_eq!(Arbi::from(-25).next_multiple_of(&Arbi::from(7)), -21);
25+
/// assert_eq!(Arbi::from(-21).next_multiple_of(&Arbi::from(-7)), -21);
26+
/// assert_eq!(Arbi::from(-25).next_multiple_of(&Arbi::from(-7)), -28);
27+
/// ```
28+
///
29+
/// Panics if `rhs` is zero:
30+
/// ```should_panic
31+
/// use arbi::Arbi;
32+
/// Arbi::from(123).next_multiple_of(&Arbi::zero());
33+
/// ```
34+
pub fn next_multiple_of(&self, rhs: &Self) -> Self {
35+
let (_, mut r) = self.divrem_floor_ref(rhs);
36+
if r.is_zero() {
37+
r.assign(self);
38+
r
39+
} else {
40+
(rhs - r) + self
41+
}
42+
}
43+
44+
/// If `rhs` is positive, return the largest value less than or equal to
45+
/// `self` that is a multiple of `rhs`. If `rhs` is negative, return the
46+
/// smallest value greater than or equal to `self` that is a multiple of
47+
/// `rhs`.
48+
///
49+
/// # Panic
50+
/// Panics if `rhs` is zero.
51+
///
52+
/// # Examples
53+
/// ```
54+
/// use arbi::Arbi;
55+
/// assert_eq!(Arbi::from(12).prev_multiple_of(&Arbi::from(6)), 12);
56+
/// assert_eq!(Arbi::from(19).prev_multiple_of(&Arbi::from(7)), 14);
57+
/// assert_eq!(Arbi::from(25).prev_multiple_of(&Arbi::from(-5)), 25);
58+
/// assert_eq!(Arbi::from(25).prev_multiple_of(&Arbi::from(-7)), 28);
59+
/// assert_eq!(Arbi::from(-21).prev_multiple_of(&Arbi::from(7)), -21);
60+
/// assert_eq!(Arbi::from(-25).prev_multiple_of(&Arbi::from(7)), -28);
61+
/// assert_eq!(Arbi::from(-21).prev_multiple_of(&Arbi::from(-7)), -21);
62+
/// assert_eq!(Arbi::from(-25).prev_multiple_of(&Arbi::from(-7)), -21);
63+
/// ```
64+
///
65+
/// Panics if `rhs` is zero:
66+
/// ```should_panic
67+
/// use arbi::Arbi;
68+
/// Arbi::from(123).prev_multiple_of(&Arbi::zero());
69+
/// ```
70+
pub fn prev_multiple_of(&self, rhs: &Self) -> Self {
71+
let (_, mut r) = self.divrem_floor_ref(rhs);
72+
if r.is_zero() {
73+
// Potentially avoid memory allocation
74+
r.assign(self);
75+
r
76+
} else {
77+
self - r
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)