malachite_nz/gaussian_integer/arithmetic/div_rem.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5// Copyright © 2022 Fredrik Johansson
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::gaussian_integer::GaussianInteger;
14use crate::gaussian_integer::arithmetic::div_exact::{
15 DOUBLE_QUOTIENT_BITS, nearest_quotient_double,
16};
17use crate::gaussian_integer::arithmetic::mul::mul_val_ref;
18use core::mem::take;
19use malachite_base::num::arithmetic::traits::{
20 AbsSquared, Conjugate, DivAssignRem, DivRem, DivRound,
21};
22use malachite_base::num::basic::traits::Zero;
23use malachite_base::rounding_modes::RoundingMode::Floor;
24
25// A dividend with this many fewer bits than the divisor (both measured as the larger of the two
26// parts' bit counts) has norm less than N(y) / 8, so the nearest quotient is 0.
27const SMALL_DIVIDEND_BITS: u64 = 2;
28
29// The nearest quotient, computed as floor((2 x conj(y) + N(y)(1 + i)) / (2 N(y))), part by part.
30fn nearest_quotient(x: &GaussianInteger, y: &GaussianInteger) -> GaussianInteger {
31 let mut t = mul_val_ref(y.conjugate(), x);
32 let mut norm = y.abs_squared();
33 t.real <<= 1u32;
34 t.imaginary <<= 1u32;
35 t.real += &norm;
36 t.imaginary += &norm;
37 norm <<= 1u32;
38 GaussianInteger {
39 real: t.real.div_round(&norm, Floor).0,
40 imaginary: t.imaginary.div_round(norm, Floor).0,
41 }
42}
43// The nearest quotient, or `None` when it is zero because the dividend is zero or much smaller than
44// the divisor.
45pub(super) fn quotient_or_zero(
46 x: &GaussianInteger,
47 y: &GaussianInteger,
48) -> Option<GaussianInteger> {
49 let y_bits = y.max_significant_bits();
50 assert!(y_bits != 0, "division by zero");
51 let x_bits = x.max_significant_bits();
52 if x_bits == 0 || x_bits + SMALL_DIVIDEND_BITS < y_bits {
53 None
54 } else {
55 Some(nearest_quotient(x, y))
56 }
57}
58
59// A port of `fmpzi_divrem_approx`: like `div_rem`, but when the operands are within 45 bits of each
60// other the quotient is computed in double precision, so it may miss the nearest quotient by one in
61// a part. The remainder is still small enough for a Euclidean step, which is all this is used for.
62pub(super) fn div_rem_approx(
63 x: &GaussianInteger,
64 y: &GaussianInteger,
65) -> (GaussianInteger, GaussianInteger) {
66 let y_bits = y.max_significant_bits();
67 assert!(y_bits != 0, "division by zero");
68 let x_bits = x.max_significant_bits();
69 if x_bits == 0 || x_bits + SMALL_DIVIDEND_BITS < y_bits {
70 (GaussianInteger::ZERO, x.clone())
71 } else if x_bits < y_bits + DOUBLE_QUOTIENT_BITS {
72 let q = nearest_quotient_double(x, y, x_bits);
73 let r = x - &q * y;
74 (q, r)
75 } else {
76 div_rem_ref_ref(x, y)
77 }
78}
79
80pub(super) fn div_rem_val_ref(
81 x: GaussianInteger,
82 y: &GaussianInteger,
83) -> (GaussianInteger, GaussianInteger) {
84 match quotient_or_zero(&x, y) {
85 Some(q) => {
86 let r = x - &q * y;
87 (q, r)
88 }
89 None => (GaussianInteger::ZERO, x),
90 }
91}
92
93pub(super) fn div_rem_ref_ref(
94 x: &GaussianInteger,
95 y: &GaussianInteger,
96) -> (GaussianInteger, GaussianInteger) {
97 match quotient_or_zero(x, y) {
98 Some(q) => {
99 let r = x - &q * y;
100 (q, r)
101 }
102 None => (GaussianInteger::ZERO, x.clone()),
103 }
104}
105
106impl DivRem<Self> for GaussianInteger {
107 type DivOutput = Self;
108 type RemOutput = Self;
109
110 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking both by value and
111 /// returning the quotient and remainder.
112 ///
113 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
114 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
115 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
116 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
117 /// smaller than the divisor.
118 ///
119 /// $$
120 /// f(x, y) = (q, x - qy), \quad \text{where } q = \left \lfloor \frac{x \bar{y}}{N(y)} +
121 /// \frac{1 + i}{2} \right \rfloor
122 /// $$
123 /// and the floor is taken on each part.
124 ///
125 /// # Worst-case complexity
126 /// $T(n) = O(n \log n \log\log n)$
127 ///
128 /// $M(n) = O(n \log n)$
129 ///
130 /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
131 /// bits of the real and imaginary parts of `self` and `other`.
132 ///
133 /// # Panics
134 /// Panics if `other` is zero.
135 ///
136 /// # Examples
137 /// ```
138 /// use malachite_base::num::arithmetic::traits::DivRem;
139 /// use malachite_nz::gaussian_integer::GaussianInteger;
140 /// use std::str::FromStr;
141 ///
142 /// // (2+i)(3) + (-1) = 5+3i
143 /// let x = GaussianInteger::from_str("5+3i").unwrap();
144 /// let y = GaussianInteger::from_str("2+i").unwrap();
145 /// let (q, r) = x.div_rem(y);
146 /// assert_eq!(q.to_string(), "3");
147 /// assert_eq!(r.to_string(), "-1");
148 /// ```
149 #[inline]
150 fn div_rem(self, other: Self) -> (Self, Self) {
151 div_rem_val_ref(self, &other)
152 }
153}
154
155impl DivRem<&Self> for GaussianInteger {
156 type DivOutput = Self;
157 type RemOutput = Self;
158
159 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking the first by value and
160 /// the second by reference and returning the quotient and remainder.
161 ///
162 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
163 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
164 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
165 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
166 /// smaller than the divisor.
167 ///
168 /// $$
169 /// f(x, y) = (q, x - qy), \quad \text{where } q = \left \lfloor \frac{x \bar{y}}{N(y)} +
170 /// \frac{1 + i}{2} \right \rfloor
171 /// $$
172 /// and the floor is taken on each part.
173 ///
174 /// # Worst-case complexity
175 /// $T(n) = O(n \log n \log\log n)$
176 ///
177 /// $M(n) = O(n \log n)$
178 ///
179 /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
180 /// bits of the real and imaginary parts of `self` and `other`.
181 ///
182 /// # Panics
183 /// Panics if `other` is zero.
184 ///
185 /// # Examples
186 /// ```
187 /// use malachite_base::num::arithmetic::traits::DivRem;
188 /// use malachite_nz::gaussian_integer::GaussianInteger;
189 /// use std::str::FromStr;
190 ///
191 /// // (2+i)(3) + (-1) = 5+3i
192 /// let x = GaussianInteger::from_str("5+3i").unwrap();
193 /// let y = GaussianInteger::from_str("2+i").unwrap();
194 /// let (q, r) = x.div_rem(&y);
195 /// assert_eq!(q.to_string(), "3");
196 /// assert_eq!(r.to_string(), "-1");
197 /// ```
198 #[inline]
199 fn div_rem(self, other: &Self) -> (Self, Self) {
200 div_rem_val_ref(self, other)
201 }
202}
203
204impl DivRem<GaussianInteger> for &GaussianInteger {
205 type DivOutput = GaussianInteger;
206 type RemOutput = GaussianInteger;
207
208 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking the first by reference
209 /// and the second by value and returning the quotient and remainder.
210 ///
211 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
212 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
213 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
214 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
215 /// smaller than the divisor.
216 ///
217 /// $$
218 /// f(x, y) = (q, x - qy), \quad \text{where } q = \left \lfloor \frac{x \bar{y}}{N(y)} +
219 /// \frac{1 + i}{2} \right \rfloor
220 /// $$
221 /// and the floor is taken on each part.
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 the maximum number of significant
229 /// bits of the real and imaginary parts of `self` and `other`.
230 ///
231 /// # Panics
232 /// Panics if `other` is zero.
233 ///
234 /// # Examples
235 /// ```
236 /// use malachite_base::num::arithmetic::traits::DivRem;
237 /// use malachite_nz::gaussian_integer::GaussianInteger;
238 /// use std::str::FromStr;
239 ///
240 /// // (2+i)(3) + (-1) = 5+3i
241 /// let x = GaussianInteger::from_str("5+3i").unwrap();
242 /// let y = GaussianInteger::from_str("2+i").unwrap();
243 /// let (q, r) = (&x).div_rem(y);
244 /// assert_eq!(q.to_string(), "3");
245 /// assert_eq!(r.to_string(), "-1");
246 /// ```
247 #[inline]
248 fn div_rem(self, other: GaussianInteger) -> (GaussianInteger, GaussianInteger) {
249 div_rem_ref_ref(self, &other)
250 }
251}
252
253impl DivRem<&GaussianInteger> for &GaussianInteger {
254 type DivOutput = GaussianInteger;
255 type RemOutput = GaussianInteger;
256
257 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking both by reference and
258 /// returning the quotient and remainder.
259 ///
260 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
261 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
262 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
263 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
264 /// smaller than the divisor.
265 ///
266 /// $$
267 /// f(x, y) = (q, x - qy), \quad \text{where } q = \left \lfloor \frac{x \bar{y}}{N(y)} +
268 /// \frac{1 + i}{2} \right \rfloor
269 /// $$
270 /// and the floor is taken on each part.
271 ///
272 /// # Worst-case complexity
273 /// $T(n) = O(n \log n \log\log n)$
274 ///
275 /// $M(n) = O(n \log n)$
276 ///
277 /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
278 /// bits of the real and imaginary parts of `self` and `other`.
279 ///
280 /// # Panics
281 /// Panics if `other` is zero.
282 ///
283 /// # Examples
284 /// ```
285 /// use malachite_base::num::arithmetic::traits::DivRem;
286 /// use malachite_nz::gaussian_integer::GaussianInteger;
287 /// use std::str::FromStr;
288 ///
289 /// // (2+i)(3) + (-1) = 5+3i
290 /// let x = GaussianInteger::from_str("5+3i").unwrap();
291 /// let y = GaussianInteger::from_str("2+i").unwrap();
292 /// let (q, r) = (&x).div_rem(&y);
293 /// assert_eq!(q.to_string(), "3");
294 /// assert_eq!(r.to_string(), "-1");
295 /// ```
296 #[inline]
297 fn div_rem(self, other: &GaussianInteger) -> (GaussianInteger, GaussianInteger) {
298 div_rem_ref_ref(self, other)
299 }
300}
301
302impl DivAssignRem<Self> for GaussianInteger {
303 type RemOutput = Self;
304
305 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`] in place, taking the
306 /// [`GaussianInteger`] on the right-hand side by value and returning the remainder.
307 ///
308 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
309 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
310 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
311 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
312 /// smaller than the divisor.
313 ///
314 /// $$
315 /// x \gets q, \quad f(x, y) = x - qy, \quad \text{where }
316 /// q = \left \lfloor \frac{x \bar{y}}{N(y)} + \frac{1 + i}{2} \right \rfloor
317 /// $$
318 /// and the floor is taken on each part.
319 ///
320 /// # Worst-case complexity
321 /// $T(n) = O(n \log n \log\log n)$
322 ///
323 /// $M(n) = O(n \log n)$
324 ///
325 /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
326 /// bits of the real and imaginary parts of `self` and `other`.
327 ///
328 /// # Panics
329 /// Panics if `other` is zero.
330 ///
331 /// # Examples
332 /// ```
333 /// use malachite_base::num::arithmetic::traits::DivAssignRem;
334 /// use malachite_nz::gaussian_integer::GaussianInteger;
335 /// use std::str::FromStr;
336 ///
337 /// // (2+i)(3) + (-1) = 5+3i
338 /// let mut x = GaussianInteger::from_str("5+3i").unwrap();
339 /// let r = x.div_assign_rem(GaussianInteger::from_str("2+i").unwrap());
340 /// assert_eq!(x.to_string(), "3");
341 /// assert_eq!(r.to_string(), "-1");
342 /// ```
343 #[inline]
344 fn div_assign_rem(&mut self, other: Self) -> Self {
345 let (q, r) = div_rem_val_ref(take(self), &other);
346 *self = q;
347 r
348 }
349}
350
351impl DivAssignRem<&Self> for GaussianInteger {
352 type RemOutput = Self;
353
354 /// Divides a [`GaussianInteger`] by another [`GaussianInteger`] in place, taking the
355 /// [`GaussianInteger`] on the right-hand side by reference and returning the remainder.
356 ///
357 /// The quotient is the Gaussian integer nearest to the exact quotient, with each part rounded
358 /// to the nearest integer and ties rounded up; the remainder is what is left over. This is the
359 /// division of the Gaussian integers as a Euclidean domain: the quotient and remainder satisfy
360 /// $x = qy + r$ and $N(r) \leq N(y) / 2$, where $N$ is the norm, so the remainder is always
361 /// smaller than the divisor.
362 ///
363 /// $$
364 /// x \gets q, \quad f(x, y) = x - qy, \quad \text{where }
365 /// q = \left \lfloor \frac{x \bar{y}}{N(y)} + \frac{1 + i}{2} \right \rfloor
366 /// $$
367 /// and the floor is taken on each part.
368 ///
369 /// # Worst-case complexity
370 /// $T(n) = O(n \log n \log\log n)$
371 ///
372 /// $M(n) = O(n \log n)$
373 ///
374 /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
375 /// bits of the real and imaginary parts of `self` and `other`.
376 ///
377 /// # Panics
378 /// Panics if `other` is zero.
379 ///
380 /// # Examples
381 /// ```
382 /// use malachite_base::num::arithmetic::traits::DivAssignRem;
383 /// use malachite_nz::gaussian_integer::GaussianInteger;
384 /// use std::str::FromStr;
385 ///
386 /// // (2+i)(3) + (-1) = 5+3i
387 /// let mut x = GaussianInteger::from_str("5+3i").unwrap();
388 /// let r = x.div_assign_rem(&GaussianInteger::from_str("2+i").unwrap());
389 /// assert_eq!(x.to_string(), "3");
390 /// assert_eq!(r.to_string(), "-1");
391 /// ```
392 #[inline]
393 fn div_assign_rem(&mut self, other: &Self) -> Self {
394 let (q, r) = div_rem_val_ref(take(self), other);
395 *self = q;
396 r
397 }
398}