Skip to content

Commit 3a1f1de

Browse files
authored
Add modular multiplicative inverse method (#82)
1 parent c954526 commit 3a1f1de

File tree

6 files changed

+362
-14
lines changed

6 files changed

+362
-14
lines changed

arbi/src/add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl Arbi {
3535
}
3636

3737
/// \\( self += y \\)
38-
fn dadd_inplace(&mut self, y: &[Digit], y_is_neg: bool) {
38+
pub(crate) fn dadd_inplace(&mut self, y: &[Digit], y_is_neg: bool) {
3939
if self.is_negative() {
4040
if y_is_neg {
4141
// x < 0, y < 0 ==> x = -|x|, y = -|y|. ==> x + y = -(|x| + |y|)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
/// Divide `self` by `rhs`, returning both a quotient and remainder:
10+
/// `(q, r)`.
11+
///
12+
/// The quotient is rounded towards negative infinity and the remainder will
13+
/// have the same sign as `rhs`.
14+
///
15+
/// # Panic
16+
/// Panics if `rhs` is zero.
17+
///
18+
/// # Examples
19+
/// ```
20+
/// use arbi::Arbi;
21+
/// let (a, b) = (Arbi::from(8), Arbi::from(3));
22+
/// let (ma, mb) = (a.negate_ref(), b.negate_ref());
23+
///
24+
/// let (q, r) = a.divrem_floor_ref(&b);
25+
/// assert_eq!(q, 2);
26+
/// assert_eq!(r, 2);
27+
///
28+
/// let (q, r) = a.divrem_floor_ref(&mb);
29+
/// assert_eq!(q, -3);
30+
/// assert_eq!(r, -1);
31+
///
32+
/// let (q, r) = ma.divrem_floor_ref(&b);
33+
/// assert_eq!(q, -3);
34+
/// assert_eq!(r, 1);
35+
///
36+
/// let (q, r) = ma.divrem_floor_ref(&mb);
37+
/// assert_eq!(q, 2);
38+
/// assert_eq!(r, -2);
39+
///
40+
/// let (q, r) = Arbi::zero().divrem_floor_ref(&a);
41+
/// assert_eq!(q, 0);
42+
/// assert_eq!(r, 0);
43+
///
44+
/// let (q, r) = Arbi::zero().divrem_floor_ref(&ma);
45+
/// assert_eq!(q, 0);
46+
/// assert_eq!(r, 0);
47+
/// ```
48+
///
49+
/// Panics if `rhs` is zero:
50+
/// ```should_panic
51+
/// use arbi::Arbi;
52+
///
53+
/// let x = Arbi::from(123456789);
54+
/// let (q, r) = x.divrem_floor_ref(&Arbi::zero());
55+
/// ```
56+
pub fn divrem_floor_ref(&self, rhs: &Self) -> (Self, Self) {
57+
let (mut q, mut r) = (Arbi::zero(), Arbi::zero());
58+
Self::fdivide(&mut q, &mut r, self, rhs);
59+
(q, r)
60+
}
61+
}

arbi/src/builtin_int_methods/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod abs_diff;
88
mod count_ones;
99
mod count_zeros;
1010
mod div_ceil;
11+
mod div_floor;
1112
mod euclid_div_and_rem;
1213
mod from_bytes;
1314
mod ilog;

arbi/src/division.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl Arbi {
198198
Self::ddiv_algo_knuth(q, r, &u.vec, &v.vec);
199199
}
200200

201-
fn ddivide(
201+
pub(crate) fn ddivide(
202202
q: &mut Self,
203203
r: &mut Self,
204204
n: &[Digit],
@@ -245,6 +245,33 @@ impl Arbi {
245245
r.neg = r.size() > 0 && n_is_neg;
246246
}
247247

248+
pub(crate) fn fddivide(
249+
q: &mut Self,
250+
r: &mut Self,
251+
n: &[Digit],
252+
d: &[Digit],
253+
n_sign: i32,
254+
d_sign: i32,
255+
) {
256+
Self::ddivide(q, r, n, d, false, false);
257+
if d_sign == -1 {
258+
r.negate_mut();
259+
}
260+
match (n_sign, d_sign) {
261+
(1, -1) | (-1, 1) => {
262+
if r.is_zero() {
263+
q.negate_mut();
264+
} else {
265+
q.negate_mut();
266+
*q -= 1;
267+
r.negate_mut();
268+
r.dadd_inplace(d, d_sign == -1); // *r += d;
269+
}
270+
}
271+
_ => {}
272+
}
273+
}
274+
248275
/// `Q = N / D, R = N % D`, in one pass.
249276
/// Panics if the divisor is zero.
250277
///
@@ -256,9 +283,15 @@ impl Arbi {
256283
/// > quotient with any fractional part discarded; if the quotient a/b is
257284
/// > representable in the type of the result, (a/b)*b + a%b is equal to a;
258285
/// > otherwise, the behavior of both a/b and a%b is undefined.
259-
fn divide(q: &mut Self, r: &mut Self, n: &Self, d: &Self) {
286+
// Truncating Division
287+
pub(crate) fn tdivide(q: &mut Self, r: &mut Self, n: &Self, d: &Self) {
260288
Self::ddivide(q, r, &n.vec, &d.vec, n.is_negative(), d.is_negative());
261289
}
290+
291+
// Floor Division
292+
pub(crate) fn fdivide(q: &mut Self, r: &mut Self, n: &Self, d: &Self) {
293+
Self::fddivide(q, r, &n.vec, &d.vec, n.signum(), d.signum());
294+
}
262295
}
263296

264297
/// See the [`div()`](#method.div) method.
@@ -268,7 +301,7 @@ impl Div<Arbi> for Arbi {
268301
fn div(self, rhs: Arbi) -> Arbi {
269302
let mut quot: Arbi = Arbi::zero();
270303
let mut rem: Arbi = Arbi::zero();
271-
Self::divide(&mut quot, &mut rem, &self, &rhs);
304+
Self::tdivide(&mut quot, &mut rem, &self, &rhs);
272305
quot
273306
}
274307
}
@@ -280,7 +313,7 @@ impl<'a> Div<&'a Arbi> for Arbi {
280313
fn div(self, rhs: &'a Arbi) -> Arbi {
281314
let mut quot: Arbi = Arbi::zero();
282315
let mut rem: Arbi = Arbi::zero();
283-
Self::divide(&mut quot, &mut rem, &self, rhs);
316+
Self::tdivide(&mut quot, &mut rem, &self, rhs);
284317
quot
285318
}
286319
}
@@ -292,7 +325,7 @@ impl<'a> Div<&'a Arbi> for &Arbi {
292325
fn div(self, rhs: &'a Arbi) -> Arbi {
293326
let mut quot: Arbi = Arbi::zero();
294327
let mut rem: Arbi = Arbi::zero();
295-
Arbi::divide(&mut quot, &mut rem, self, rhs);
328+
Arbi::tdivide(&mut quot, &mut rem, self, rhs);
296329
quot
297330
}
298331
}
@@ -302,7 +335,7 @@ impl DivAssign<Arbi> for Arbi {
302335
fn div_assign(&mut self, rhs: Arbi) {
303336
let mut quot: Arbi = Arbi::zero();
304337
let mut rem: Arbi = Arbi::zero();
305-
Self::divide(&mut quot, &mut rem, self, &rhs);
338+
Self::tdivide(&mut quot, &mut rem, self, &rhs);
306339
*self = quot;
307340
}
308341
}
@@ -312,7 +345,7 @@ impl<'a> DivAssign<&'a Arbi> for Arbi {
312345
fn div_assign(&mut self, rhs: &'a Arbi) {
313346
let mut quot: Arbi = Arbi::zero();
314347
let mut rem: Arbi = Arbi::zero();
315-
Self::divide(&mut quot, &mut rem, self, rhs);
348+
Self::tdivide(&mut quot, &mut rem, self, rhs);
316349
*self = quot;
317350
}
318351
}
@@ -324,7 +357,7 @@ impl Rem<Arbi> for Arbi {
324357
fn rem(self, rhs: Arbi) -> Arbi {
325358
let mut quot: Arbi = Arbi::zero();
326359
let mut rem: Arbi = Arbi::zero();
327-
Self::divide(&mut quot, &mut rem, &self, &rhs);
360+
Self::tdivide(&mut quot, &mut rem, &self, &rhs);
328361
rem
329362
}
330363
}
@@ -336,7 +369,7 @@ impl<'a> Rem<&'a Arbi> for Arbi {
336369
fn rem(self, rhs: &'a Arbi) -> Arbi {
337370
let mut quot: Arbi = Arbi::zero();
338371
let mut rem: Arbi = Arbi::zero();
339-
Self::divide(&mut quot, &mut rem, &self, rhs);
372+
Self::tdivide(&mut quot, &mut rem, &self, rhs);
340373
rem
341374
}
342375
}
@@ -348,7 +381,7 @@ impl<'a> Rem<&'a Arbi> for &Arbi {
348381
fn rem(self, rhs: &'a Arbi) -> Arbi {
349382
let mut quot: Arbi = Arbi::zero();
350383
let mut rem: Arbi = Arbi::zero();
351-
Arbi::divide(&mut quot, &mut rem, self, rhs);
384+
Arbi::tdivide(&mut quot, &mut rem, self, rhs);
352385
rem
353386
}
354387
}
@@ -358,7 +391,7 @@ impl RemAssign<Arbi> for Arbi {
358391
fn rem_assign(&mut self, rhs: Arbi) {
359392
let mut quot: Arbi = Arbi::zero();
360393
let mut rem: Arbi = Arbi::zero();
361-
Self::divide(&mut quot, &mut rem, self, &rhs);
394+
Self::tdivide(&mut quot, &mut rem, self, &rhs);
362395
*self = rem;
363396
}
364397
}
@@ -368,7 +401,7 @@ impl<'a> RemAssign<&'a Arbi> for Arbi {
368401
fn rem_assign(&mut self, rhs: &'a Arbi) {
369402
let mut quot: Arbi = Arbi::zero();
370403
let mut rem: Arbi = Arbi::zero();
371-
Self::divide(&mut quot, &mut rem, self, rhs);
404+
Self::tdivide(&mut quot, &mut rem, self, rhs);
372405
*self = rem;
373406
}
374407
}
@@ -509,7 +542,7 @@ impl Arbi {
509542
pub fn divrem(&self, other: &Arbi) -> (Arbi, Arbi) {
510543
let mut quot: Arbi = Arbi::zero();
511544
let mut rem: Arbi = Arbi::zero();
512-
Self::divide(&mut quot, &mut rem, self, other);
545+
Self::tdivide(&mut quot, &mut rem, self, other);
513546
(quot, rem)
514547
}
515548
}

0 commit comments

Comments
 (0)