malachite_base/num/arithmetic/mod_sub.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5// Copyright © 2010 William Hart
6//
7// Copyright © 2021 Fredrik Johansson
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::num::arithmetic::traits::{ModSub, ModSubAssign};
16use crate::num::basic::unsigneds::PrimitiveUnsigned;
17
18fn mod_sub<T: PrimitiveUnsigned>(x: T, y: T, m: T) -> T {
19 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
20 assert!(y < m, "y must be reduced mod m, but {y} >= {m}");
21 let diff = x.wrapping_sub(y);
22 if x < y { m.wrapping_add(diff) } else { diff }
23}
24
25macro_rules! impl_mod_sub {
26 ($t:ident) => {
27 impl ModSub<$t> for $t {
28 type Output = $t;
29
30 /// Subtracts two numbers modulo a third number $m$. The inputs must be already reduced
31 /// modulo $m$.
32 ///
33 /// $f(x, y, m) = z$, where $x, y, z < m$ and $x - y \equiv z \mod m$.
34 ///
35 /// # Worst-case complexity
36 /// Constant time and additional memory.
37 ///
38 /// # Panics
39 /// Panics if `self` or `other` are greater than or equal to `m`.
40 ///
41 /// # Examples
42 /// See [here](super::mod_sub#mod_sub).
43 ///
44 /// This is equivalent to `nmod_sub` from `nmod.h`, FLINT 2.7.1.
45 #[inline]
46 fn mod_sub(self, other: $t, m: $t) -> $t {
47 mod_sub(self, other, m)
48 }
49 }
50
51 impl ModSubAssign<$t> for $t {
52 /// Subtracts two numbers modulo a third number $m$, in place. The inputs must be
53 /// already reduced modulo $m$.
54 ///
55 /// $x \gets z$, where $x, y, z < m$ and $x - y \equiv z \mod m$.
56 ///
57 /// # Worst-case complexity
58 /// Constant time and additional memory.
59 ///
60 /// # Panics
61 /// Panics if `self` or `other` are greater than or equal to `m`.
62 ///
63 /// # Examples
64 /// See [here](super::mod_sub#mod_sub_assign).
65 ///
66 /// This is equivalent to `nmod_sub` from `nmod.h`, FLINT 2.7.1, where the result is
67 /// assigned to `a`.
68 #[inline]
69 fn mod_sub_assign(&mut self, other: $t, m: $t) {
70 *self = self.mod_sub(other, m);
71 }
72 }
73 };
74}
75apply_to_unsigneds!(impl_mod_sub);