malachite_base/num/arithmetic/mod_op.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{
10 CeilingMod, CeilingModAssign, Mod, ModAssign, NegMod, NegModAssign, UnsignedAbs,
11};
12use crate::num::basic::signeds::PrimitiveSigned;
13use crate::num::basic::unsigneds::PrimitiveUnsigned;
14use crate::num::conversion::traits::ExactFrom;
15
16fn neg_mod_unsigned<T: PrimitiveUnsigned>(x: T, other: T) -> T {
17 let remainder = x % other;
18 if remainder == T::ZERO {
19 T::ZERO
20 } else {
21 other - remainder
22 }
23}
24
25fn neg_mod_assign_unsigned<T: PrimitiveUnsigned>(x: &mut T, other: T) {
26 *x %= other;
27 if *x != T::ZERO {
28 *x = other - *x;
29 }
30}
31
32macro_rules! impl_mod_unsigned {
33 ($t:ident) => {
34 impl Mod<$t> for $t {
35 type Output = $t;
36
37 /// Divides a number by another number, returning just the remainder.
38 ///
39 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy + r$
40 /// and $0 \leq r < y$.
41 ///
42 /// $$
43 /// f(x, y) = x - y\left \lfloor \frac{x}{y} \right \rfloor.
44 /// $$
45 ///
46 /// This function is called `mod_op` rather than `mod` because `mod` is a Rust keyword.
47 ///
48 /// # Worst-case complexity
49 /// Constant time and additional memory.
50 ///
51 /// # Panics
52 /// Panics if `other` is 0.
53 ///
54 /// # Examples
55 /// See [here](super::mod_op#mod_op).
56 #[inline]
57 fn mod_op(self, other: $t) -> $t {
58 self % other
59 }
60 }
61
62 impl ModAssign<$t> for $t {
63 /// Divides a number by another number, replacing the first number by the remainder.
64 ///
65 /// If the quotient were computed, he quotient and remainder would satisfy $x = qy + r$
66 /// and $0 \leq r < y$.
67 ///
68 /// $$
69 /// x \gets x - y\left \lfloor \frac{x}{y} \right \rfloor.
70 /// $$
71 ///
72 /// # Worst-case complexity
73 /// Constant time and additional memory.
74 ///
75 /// # Panics
76 /// Panics if `other` is 0.
77 ///
78 /// # Examples
79 /// See [here](super::mod_op#mod_assign).
80 #[inline]
81 fn mod_assign(&mut self, other: $t) {
82 *self %= other;
83 }
84 }
85
86 impl NegMod<$t> for $t {
87 type Output = $t;
88
89 /// Divides the negative of a number by another number, returning just the remainder.
90 ///
91 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy - r$
92 /// and $0 \leq r < y$.
93 ///
94 /// $$
95 /// f(x, y) = y\left \lceil \frac{x}{y} \right \rceil - x.
96 /// $$
97 ///
98 /// # Worst-case complexity
99 /// Constant time and additional memory.
100 ///
101 /// # Panics
102 /// Panics if `other` is 0.
103 ///
104 /// # Examples
105 /// See [here](super::mod_op#neg_mod).
106 #[inline]
107 fn neg_mod(self, other: $t) -> $t {
108 neg_mod_unsigned(self, other)
109 }
110 }
111
112 impl NegModAssign<$t> for $t {
113 /// Divides the negative of a number by another number, returning just the remainder.
114 ///
115 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy - r$
116 /// and $0 \leq r < y$.
117 ///
118 /// $$
119 /// x \gets y\left \lceil \frac{x}{y} \right \rceil - x.
120 /// $$
121 ///
122 /// # Worst-case complexity
123 /// Constant time and additional memory.
124 ///
125 /// # Panics
126 /// Panics if `other` is 0.
127 ///
128 /// # Examples
129 /// See [here](super::mod_op#neg_mod_assign).
130 #[inline]
131 fn neg_mod_assign(&mut self, other: $t) {
132 neg_mod_assign_unsigned(self, other);
133 }
134 }
135 };
136}
137apply_to_unsigneds!(impl_mod_unsigned);
138
139fn mod_op_signed<
140 U: PrimitiveUnsigned,
141 S: ExactFrom<U> + PrimitiveSigned + UnsignedAbs<Output = U>,
142>(
143 x: S,
144 other: S,
145) -> S {
146 let remainder = if (x >= S::ZERO) == (other >= S::ZERO) {
147 x.unsigned_abs() % other.unsigned_abs()
148 } else {
149 x.unsigned_abs().neg_mod(other.unsigned_abs())
150 };
151 if other >= S::ZERO {
152 S::exact_from(remainder)
153 } else {
154 -S::exact_from(remainder)
155 }
156}
157
158fn ceiling_mod_signed<
159 U: PrimitiveUnsigned,
160 S: ExactFrom<U> + PrimitiveSigned + UnsignedAbs<Output = U>,
161>(
162 x: S,
163 other: S,
164) -> S {
165 let remainder = if (x >= S::ZERO) == (other >= S::ZERO) {
166 x.unsigned_abs().neg_mod(other.unsigned_abs())
167 } else {
168 x.unsigned_abs() % other.unsigned_abs()
169 };
170 if other >= S::ZERO {
171 -S::exact_from(remainder)
172 } else {
173 S::exact_from(remainder)
174 }
175}
176
177macro_rules! impl_mod_signed {
178 ($t:ident) => {
179 impl Mod<$t> for $t {
180 type Output = $t;
181
182 /// Divides a number by another number, returning just the remainder. The remainder has
183 /// the same sign as the second number.
184 ///
185 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy + r$
186 /// and $0 \leq |r| < |y|$.
187 ///
188 /// $$
189 /// f(x, y) = x - y\left \lfloor \frac{x}{y} \right \rfloor.
190 /// $$
191 ///
192 /// This function is called `mod_op` rather than `mod` because `mod` is a Rust keyword.
193 ///
194 /// # Worst-case complexity
195 /// Constant time and additional memory.
196 ///
197 /// # Panics
198 /// Panics if `other` is 0.
199 ///
200 /// # Examples
201 /// See [here](super::mod_op#mod_op).
202 #[inline]
203 fn mod_op(self, other: $t) -> $t {
204 mod_op_signed(self, other)
205 }
206 }
207
208 impl ModAssign<$t> for $t {
209 /// Divides a number by another number, replacing the first number by the remainder. The
210 /// remainder has the same sign as the second number.
211 ///
212 /// If the quotient were computed, he quotient and remainder would satisfy $x = qy + r$
213 /// and $0 \leq |r| < |y|$.
214 ///
215 /// $$
216 /// x \gets x - y\left \lfloor \frac{x}{y} \right \rfloor.
217 /// $$
218 ///
219 /// # Worst-case complexity
220 /// Constant time and additional memory.
221 ///
222 /// # Panics
223 /// Panics if `other` is 0.
224 ///
225 /// # Examples
226 /// See [here](super::mod_op#mod_assign).
227 #[inline]
228 fn mod_assign(&mut self, other: $t) {
229 *self = self.mod_op(other);
230 }
231 }
232
233 impl CeilingMod<$t> for $t {
234 type Output = $t;
235
236 /// Divides a number by another number, returning just the remainder. The remainder has
237 /// the opposite sign as the second number.
238 ///
239 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy + r$
240 /// and $0 \leq |r| < |y|$.
241 ///
242 /// $$
243 /// f(x, y) = x - y\left \lceil \frac{x}{y} \right \rceil.
244 /// $$
245 ///
246 /// # Worst-case complexity
247 /// Constant time and additional memory.
248 ///
249 /// # Panics
250 /// Panics if `other` is 0.
251 ///
252 /// # Examples
253 /// See [here](super::mod_op#ceiling_mod).
254 #[inline]
255 fn ceiling_mod(self, other: $t) -> $t {
256 ceiling_mod_signed(self, other)
257 }
258 }
259
260 impl CeilingModAssign<$t> for $t {
261 /// Divides a number by another number, replacing the first number by the remainder. The
262 /// remainder has the opposite sign as the second number.
263 ///
264 /// If the quotient were computed, the quotient and remainder would satisfy $x = qy + r$
265 /// and $0 \leq |r| < |y|$.
266 ///
267 /// $$
268 /// x \gets x - y\left \lceil\frac{x}{y} \right \rceil.
269 /// $$
270 ///
271 /// # Worst-case complexity
272 /// Constant time and additional memory.
273 ///
274 /// # Panics
275 /// Panics if `other` is 0.
276 ///
277 /// # Examples
278 /// See [here](super::mod_op#ceiling_mod_assign).
279 #[inline]
280 fn ceiling_mod_assign(&mut self, other: $t) {
281 *self = self.ceiling_mod(other);
282 }
283 }
284 };
285}
286apply_to_signeds!(impl_mod_signed);