malachite_base/num/arithmetic/mod_add.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::{ModAdd, ModAddAssign};
16use crate::num::basic::unsigneds::PrimitiveUnsigned;
17
18fn mod_add<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 neg = m - x;
22 if neg > y { x + y } else { y - neg }
23}
24
25fn mod_add_assign<T: PrimitiveUnsigned>(x: &mut T, y: T, m: T) {
26 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
27 assert!(y < m, "y must be reduced mod m, but {y} >= {m}");
28 let neg = m - *x;
29 if neg > y {
30 *x += y;
31 } else {
32 *x = y - neg;
33 }
34}
35
36macro_rules! impl_mod_add {
37 ($t:ident) => {
38 impl ModAdd<$t> for $t {
39 type Output = $t;
40
41 /// Adds two numbers modulo a third number $m$. The inputs must be already reduced
42 /// modulo $m$.
43 ///
44 /// $f(x, y, m) = z$, where $x, y, z < m$ and $x + y \equiv z \mod m$.
45 ///
46 /// # Worst-case complexity
47 /// Constant time and additional memory.
48 ///
49 /// # Panics
50 /// Panics if `self` or `other` are greater than or equal to `m`.
51 ///
52 /// # Examples
53 /// See [here](super::mod_add#mod_add).
54 ///
55 /// This is equivalent to `nmod_add` from `nmod.h`, FLINT 2.7.1.
56 #[inline]
57 fn mod_add(self, other: $t, m: $t) -> $t {
58 mod_add(self, other, m)
59 }
60 }
61
62 impl ModAddAssign<$t> for $t {
63 /// Adds two numbers modulo a third number $m$, in place. The inputs must be already
64 /// reduced modulo $m$.
65 ///
66 /// $x \gets z$, where $x, y, z < m$ and $x + y \equiv z \mod m$.
67 ///
68 /// # Worst-case complexity
69 /// Constant time and additional memory.
70 ///
71 /// # Panics
72 /// Panics if `self` or `other` are greater than or equal to `m`.
73 ///
74 /// # Examples
75 /// See [here](super::mod_add#mod_add_assign).
76 ///
77 /// This is equivalent to `nmod_add` from `nmod.h`, FLINT 2.7.1, where the result is
78 /// assigned to `a`.
79 #[inline]
80 fn mod_add_assign(&mut self, other: $t, m: $t) {
81 mod_add_assign(self, other, m);
82 }
83 }
84 };
85}
86apply_to_unsigneds!(impl_mod_add);