Skip to main content

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}