Skip to main content

malachite_nz/integer/arithmetic/
balanced_mod.rs

1// Copyright © 2026 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::integer::Integer;
10use crate::natural::Natural;
11use core::cmp::Ordering::Less;
12use malachite_base::num::arithmetic::traits::{BalancedMod, BalancedModAssign, ModEuclidean};
13use malachite_base::num::comparison::traits::OrdDouble;
14
15// The Euclidean remainder already lies in [0, |m|), so the balanced one is that remainder when it
16// is at most half the modulus, and that remainder less the modulus otherwise. A remainder of
17// exactly half the modulus stays positive, which puts the endpoint at the top of the range.
18fn balanced_mod_helper(x: &Integer, m: &Integer) -> Integer {
19    let r: Natural = x.mod_euclidean(m);
20    let abs_m = m.unsigned_abs_ref();
21    // `r <= abs_m >> 1` is exactly `2r <= abs_m`: for an integer `r`, `r <= floor(x)` iff `r <= x`.
22    // Phrasing it as the latter lets `cmp_double` answer it without building either value.
23    if abs_m.cmp_double(&r) == Less {
24        Integer::from(r) - Integer::from(abs_m)
25    } else {
26        Integer::from(r)
27    }
28}
29
30impl BalancedMod<Self> for Integer {
31    type Output = Self;
32
33    /// Divides an [`Integer`] by another [`Integer`], returning the balanced remainder: the
34    /// representative of `self` modulo `other` that is closest to zero, taking both [`Integer`]s by
35    /// value.
36    ///
37    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$ and $r \equiv x \bmod y$, which
38    /// determine it uniquely. A remainder of exactly $|y|/2$ is positive. Only the magnitude of
39    /// `other` matters, so negating it leaves the result unchanged.
40    ///
41    /// # Worst-case complexity
42    /// $T(n) = O(n \log n \log \log n)$
43    ///
44    /// $M(n) = O(n \log n)$
45    ///
46    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
47    ///
48    /// # Panics
49    /// Panics if `other` is zero.
50    ///
51    /// # Examples
52    /// ```
53    /// use malachite_base::num::arithmetic::traits::BalancedMod;
54    /// use malachite_nz::integer::Integer;
55    ///
56    /// assert_eq!(Integer::from(23).balanced_mod(Integer::from(10)), 3);
57    /// // 7 is more than half of 10, so the representative closest to zero is negative
58    /// assert_eq!(Integer::from(27).balanced_mod(Integer::from(10)), -3);
59    /// // only the magnitude of the modulus matters
60    /// assert_eq!(Integer::from(27).balanced_mod(Integer::from(-10)), -3);
61    /// ```
62    #[inline]
63    fn balanced_mod(self, other: Self) -> Self {
64        balanced_mod_helper(&self, &other)
65    }
66}
67
68impl BalancedMod<&Self> for Integer {
69    type Output = Self;
70
71    /// Divides an [`Integer`] by another [`Integer`], returning the balanced remainder: the
72    /// representative of `self` modulo `other` that is closest to zero, taking the first
73    /// [`Integer`] by value and the second by reference.
74    ///
75    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$ and $r \equiv x \bmod y$, which
76    /// determine it uniquely. A remainder of exactly $|y|/2$ is positive. Only the magnitude of
77    /// `other` matters, so negating it leaves the result unchanged.
78    ///
79    /// # Worst-case complexity
80    /// $T(n) = O(n \log n \log \log n)$
81    ///
82    /// $M(n) = O(n \log n)$
83    ///
84    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
85    ///
86    /// # Panics
87    /// Panics if `other` is zero.
88    ///
89    /// # Examples
90    /// ```
91    /// use malachite_base::num::arithmetic::traits::BalancedMod;
92    /// use malachite_nz::integer::Integer;
93    ///
94    /// assert_eq!(Integer::from(23).balanced_mod(&Integer::from(10)), 3);
95    /// // 7 is more than half of 10, so the representative closest to zero is negative
96    /// assert_eq!(Integer::from(27).balanced_mod(&Integer::from(10)), -3);
97    /// // only the magnitude of the modulus matters
98    /// assert_eq!(Integer::from(27).balanced_mod(&Integer::from(-10)), -3);
99    /// ```
100    #[inline]
101    fn balanced_mod(self, other: &Self) -> Self {
102        balanced_mod_helper(&self, other)
103    }
104}
105
106impl BalancedMod<Integer> for &Integer {
107    type Output = Integer;
108
109    /// Divides an [`Integer`] by another [`Integer`], returning the balanced remainder: the
110    /// representative of `self` modulo `other` that is closest to zero, taking the first
111    /// [`Integer`] by reference and the second by value.
112    ///
113    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$ and $r \equiv x \bmod y$, which
114    /// determine it uniquely. A remainder of exactly $|y|/2$ is positive. Only the magnitude of
115    /// `other` matters, so negating it leaves the result unchanged.
116    ///
117    /// # Worst-case complexity
118    /// $T(n) = O(n \log n \log \log n)$
119    ///
120    /// $M(n) = O(n \log n)$
121    ///
122    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
123    ///
124    /// # Panics
125    /// Panics if `other` is zero.
126    ///
127    /// # Examples
128    /// ```
129    /// use malachite_base::num::arithmetic::traits::BalancedMod;
130    /// use malachite_nz::integer::Integer;
131    ///
132    /// assert_eq!((&Integer::from(23)).balanced_mod(Integer::from(10)), 3);
133    /// // 7 is more than half of 10, so the representative closest to zero is negative
134    /// assert_eq!((&Integer::from(27)).balanced_mod(Integer::from(10)), -3);
135    /// // only the magnitude of the modulus matters
136    /// assert_eq!((&Integer::from(27)).balanced_mod(Integer::from(-10)), -3);
137    /// ```
138    #[inline]
139    fn balanced_mod(self, other: Integer) -> Integer {
140        balanced_mod_helper(self, &other)
141    }
142}
143
144impl BalancedMod<&Integer> for &Integer {
145    type Output = Integer;
146
147    /// Divides an [`Integer`] by another [`Integer`], returning the balanced remainder: the
148    /// representative of `self` modulo `other` that is closest to zero, taking both [`Integer`]s by
149    /// reference.
150    ///
151    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$ and $r \equiv x \bmod y$, which
152    /// determine it uniquely. A remainder of exactly $|y|/2$ is positive. Only the magnitude of
153    /// `other` matters, so negating it leaves the result unchanged.
154    ///
155    /// # Worst-case complexity
156    /// $T(n) = O(n \log n \log \log n)$
157    ///
158    /// $M(n) = O(n \log n)$
159    ///
160    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
161    ///
162    /// # Panics
163    /// Panics if `other` is zero.
164    ///
165    /// # Examples
166    /// ```
167    /// use malachite_base::num::arithmetic::traits::BalancedMod;
168    /// use malachite_nz::integer::Integer;
169    ///
170    /// assert_eq!((&Integer::from(23)).balanced_mod(&Integer::from(10)), 3);
171    /// // 7 is more than half of 10, so the representative closest to zero is negative
172    /// assert_eq!((&Integer::from(27)).balanced_mod(&Integer::from(10)), -3);
173    /// // only the magnitude of the modulus matters
174    /// assert_eq!((&Integer::from(27)).balanced_mod(&Integer::from(-10)), -3);
175    /// ```
176    #[inline]
177    fn balanced_mod(self, other: &Integer) -> Integer {
178        balanced_mod_helper(self, other)
179    }
180}
181
182impl BalancedModAssign<Self> for Integer {
183    /// Divides an [`Integer`] by another [`Integer`], replacing the first [`Integer`] by the
184    /// balanced remainder: the representative of `self` modulo `other` that is closest to zero. The
185    /// [`Integer`] on the right-hand side is taken by value.
186    ///
187    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$; a remainder of exactly $|y|/2$ is
188    /// positive.
189    ///
190    /// # Worst-case complexity
191    /// $T(n) = O(n \log n \log \log n)$
192    ///
193    /// $M(n) = O(n \log n)$
194    ///
195    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
196    ///
197    /// # Panics
198    /// Panics if `other` is zero.
199    ///
200    /// # Examples
201    /// ```
202    /// use malachite_base::num::arithmetic::traits::BalancedModAssign;
203    /// use malachite_nz::integer::Integer;
204    ///
205    /// let mut x = Integer::from(27);
206    /// x.balanced_mod_assign(Integer::from(10));
207    /// assert_eq!(x, -3);
208    /// ```
209    #[inline]
210    fn balanced_mod_assign(&mut self, other: Self) {
211        *self = balanced_mod_helper(self, &other);
212    }
213}
214
215impl BalancedModAssign<&Self> for Integer {
216    /// Divides an [`Integer`] by another [`Integer`], replacing the first [`Integer`] by the
217    /// balanced remainder: the representative of `self` modulo `other` that is closest to zero. The
218    /// [`Integer`] on the right-hand side is taken by reference.
219    ///
220    /// The remainder $r$ satisfies $-|y|/2 < r \leq |y|/2$; a remainder of exactly $|y|/2$ is
221    /// positive.
222    ///
223    /// # Worst-case complexity
224    /// $T(n) = O(n \log n \log \log n)$
225    ///
226    /// $M(n) = O(n \log n)$
227    ///
228    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
229    ///
230    /// # Panics
231    /// Panics if `other` is zero.
232    ///
233    /// # Examples
234    /// ```
235    /// use malachite_base::num::arithmetic::traits::BalancedModAssign;
236    /// use malachite_nz::integer::Integer;
237    ///
238    /// let mut x = Integer::from(27);
239    /// x.balanced_mod_assign(&Integer::from(10));
240    /// assert_eq!(x, -3);
241    /// ```
242    #[inline]
243    fn balanced_mod_assign(&mut self, other: &Self) {
244        *self = balanced_mod_helper(self, other);
245    }
246}