Skip to main content

malachite_nz/gaussian_integer/arithmetic/
div_exact.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::mul::{mul_val_ref, mul_val_val};
15use crate::integer::Integer;
16use core::mem::take;
17use malachite_base::num::arithmetic::traits::{
18    AbsSquared, Conjugate, DivExact, DivExactAssign, DivI, Floor, PowerOf2,
19};
20use malachite_base::num::basic::traits::Zero;
21use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom, SciMantissaAndExponent};
22use malachite_base::rounding_modes::RoundingMode::Down;
23
24// Quotients this small are computed in double precision, as in `fmpzi_divexact`: with the quotient
25// known to be exact and below 2^45, the rounding errors of the double-precision conjugate product
26// and norm stay well below 1/2, so rounding to the nearest integer recovers it.
27pub(super) const DOUBLE_QUOTIENT_BITS: u64 = 45;
28
29// Above this size the operands are scaled by 2^(-x_bits) before conversion to doubles, which keeps
30// the intermediate products finite without changing the quotient.
31const DOUBLE_SCALING_BITS: u64 = 500;
32
33// `fmpz_get_d` truncates toward zero.
34fn to_f64_truncated(x: &Integer) -> f64 {
35    f64::rounding_from(x, Down).0
36}
37
38// An approximation to x * 2^(-shift), as in `fmpz_get_d_2exp` followed by `d_mul_2exp`; the
39// exponent is clamped at -1024 as FLINT does, so the result can underflow to a subnormal or to zero
40// only when it would be negligible anyway.
41fn to_f64_scaled(x: &Integer, shift: u64) -> f64 {
42    if *x == 0u32 {
43        return 0.0;
44    }
45    let (m, e): (f64, u64) = x.unsigned_abs_ref().sci_mantissa_and_exponent();
46    let v = m * f64::power_of_2((i64::exact_from(e) - i64::exact_from(shift)).max(-1024));
47    if *x < 0u32 { -v } else { v }
48}
49
50// The double-precision path of `fmpzi_divexact` and `fmpzi_divrem_approx`: the nearest-integer
51// rounding of the exact quotient x * conj(y) / N(y), evaluated in doubles. Exact when the division
52// is, and otherwise within one of the nearest quotient in each part.
53pub(super) fn nearest_quotient_double(
54    x: &GaussianInteger,
55    y: &GaussianInteger,
56    x_bits: u64,
57) -> GaussianInteger {
58    let (a, b, c, d) = if x_bits < DOUBLE_SCALING_BITS {
59        (
60            to_f64_truncated(&x.real),
61            to_f64_truncated(&x.imaginary),
62            to_f64_truncated(&y.real),
63            to_f64_truncated(&y.imaginary),
64        )
65    } else {
66        (
67            to_f64_scaled(&x.real, x_bits),
68            to_f64_scaled(&x.imaginary, x_bits),
69            to_f64_scaled(&y.real, x_bits),
70            to_f64_scaled(&y.imaginary, x_bits),
71        )
72    };
73    let t = a * c + b * d;
74    let u = b * c - a * d;
75    let v = c * c + d * d;
76    let w = 0.5 / v;
77    let t = (2.0 * t + v) * w;
78    let u = (2.0 * u + v) * w;
79    GaussianInteger {
80        real: Integer::exact_from(Floor::floor(t)),
81        imaginary: Integer::exact_from(Floor::floor(u)),
82    }
83}
84
85// The general path: multiply by the conjugate and divide both parts exactly by the norm.
86fn div_exact_general(t: GaussianInteger, norm: Integer) -> GaussianInteger {
87    GaussianInteger {
88        real: t.real.div_exact(&norm),
89        imaginary: t.imaginary.div_exact(norm),
90    }
91}
92
93// `fmpzi_divexact` also has a tier for very unbalanced operands, where both are truncated and an
94// approximate division of the truncated values yields the exact quotient; it needs
95// `fmpzi_divrem_approx`, which will be ported along with the Gaussian GCD, and until then such
96// operands take the general path.
97fn div_exact_val_ref(x: GaussianInteger, y: &GaussianInteger) -> GaussianInteger {
98    if y.imaginary == 0u32 {
99        assert!(y.real != 0u32, "division by zero");
100        return GaussianInteger {
101            real: x.real.div_exact(&y.real),
102            imaginary: x.imaginary.div_exact(&y.real),
103        };
104    } else if y.real == 0u32 {
105        return GaussianInteger {
106            real: x.real.div_exact(&y.imaginary),
107            imaginary: x.imaginary.div_exact(&y.imaginary),
108        }
109        .div_i();
110    }
111    let x_bits = x.max_significant_bits();
112    if x_bits == 0 {
113        return GaussianInteger::ZERO;
114    }
115    let y_bits = y.max_significant_bits();
116    if x_bits < y_bits + DOUBLE_QUOTIENT_BITS {
117        nearest_quotient_double(&x, y, x_bits)
118    } else {
119        let norm = y.abs_squared();
120        div_exact_general(mul_val_val(x, y.conjugate()), norm)
121    }
122}
123
124fn div_exact_ref_ref(x: &GaussianInteger, y: &GaussianInteger) -> GaussianInteger {
125    if y.imaginary == 0u32 {
126        assert!(y.real != 0u32, "division by zero");
127        return GaussianInteger {
128            real: (&x.real).div_exact(&y.real),
129            imaginary: (&x.imaginary).div_exact(&y.real),
130        };
131    } else if y.real == 0u32 {
132        return GaussianInteger {
133            real: (&x.real).div_exact(&y.imaginary),
134            imaginary: (&x.imaginary).div_exact(&y.imaginary),
135        }
136        .div_i();
137    }
138    let x_bits = x.max_significant_bits();
139    if x_bits == 0 {
140        return GaussianInteger::ZERO;
141    }
142    let y_bits = y.max_significant_bits();
143    if x_bits < y_bits + DOUBLE_QUOTIENT_BITS {
144        nearest_quotient_double(x, y, x_bits)
145    } else {
146        let norm = y.abs_squared();
147        div_exact_general(mul_val_ref(y.conjugate(), x), norm)
148    }
149}
150
151impl DivExact<Self> for GaussianInteger {
152    type Output = Self;
153
154    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking both by value. The
155    /// first [`GaussianInteger`] must be exactly divisible by the second. If it isn't, this
156    /// function may panic or return a meaningless result.
157    ///
158    /// $$
159    /// f(x, y) = \frac{x}{y}.
160    /// $$
161    ///
162    /// # Worst-case complexity
163    /// $T(n) = O(n \log n \log\log n)$
164    ///
165    /// $M(n) = O(n \log n)$
166    ///
167    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
168    /// bits of the real and imaginary parts of `self` and `other`.
169    ///
170    /// # Panics
171    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
172    ///
173    /// # Examples
174    /// ```
175    /// use malachite_base::num::arithmetic::traits::DivExact;
176    /// use malachite_nz::gaussian_integer::GaussianInteger;
177    /// use std::str::FromStr;
178    ///
179    /// // (3+4i)(5-2i) = 23+14i
180    /// let x = GaussianInteger::from_str("23+14i").unwrap();
181    /// let y = GaussianInteger::from_str("5-2i").unwrap();
182    /// assert_eq!((x.div_exact(y)).to_string(), "3+4i");
183    /// ```
184    #[inline]
185    fn div_exact(self, other: Self) -> Self {
186        div_exact_val_ref(self, &other)
187    }
188}
189
190impl DivExact<&Self> for GaussianInteger {
191    type Output = Self;
192
193    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking the first by value and
194    /// the second by reference. The first [`GaussianInteger`] must be exactly divisible by the
195    /// second. If it isn't, this function may panic or return a meaningless result.
196    ///
197    /// $$
198    /// f(x, y) = \frac{x}{y}.
199    /// $$
200    ///
201    /// # Worst-case complexity
202    /// $T(n) = O(n \log n \log\log n)$
203    ///
204    /// $M(n) = O(n \log n)$
205    ///
206    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
207    /// bits of the real and imaginary parts of `self` and `other`.
208    ///
209    /// # Panics
210    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
211    ///
212    /// # Examples
213    /// ```
214    /// use malachite_base::num::arithmetic::traits::DivExact;
215    /// use malachite_nz::gaussian_integer::GaussianInteger;
216    /// use std::str::FromStr;
217    ///
218    /// // (3+4i)(5-2i) = 23+14i
219    /// let x = GaussianInteger::from_str("23+14i").unwrap();
220    /// let y = GaussianInteger::from_str("5-2i").unwrap();
221    /// assert_eq!((x.div_exact(&y)).to_string(), "3+4i");
222    /// ```
223    #[inline]
224    fn div_exact(self, other: &Self) -> Self {
225        div_exact_val_ref(self, other)
226    }
227}
228
229impl DivExact<GaussianInteger> for &GaussianInteger {
230    type Output = GaussianInteger;
231
232    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking the first by reference
233    /// and the second by value. The first [`GaussianInteger`] must be exactly divisible by the
234    /// second. If it isn't, this function may panic or return a meaningless result.
235    ///
236    /// $$
237    /// f(x, y) = \frac{x}{y}.
238    /// $$
239    ///
240    /// # Worst-case complexity
241    /// $T(n) = O(n \log n \log\log n)$
242    ///
243    /// $M(n) = O(n \log n)$
244    ///
245    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
246    /// bits of the real and imaginary parts of `self` and `other`.
247    ///
248    /// # Panics
249    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
250    ///
251    /// # Examples
252    /// ```
253    /// use malachite_base::num::arithmetic::traits::DivExact;
254    /// use malachite_nz::gaussian_integer::GaussianInteger;
255    /// use std::str::FromStr;
256    ///
257    /// // (3+4i)(5-2i) = 23+14i
258    /// let x = GaussianInteger::from_str("23+14i").unwrap();
259    /// let y = GaussianInteger::from_str("5-2i").unwrap();
260    /// assert_eq!(((&x).div_exact(y)).to_string(), "3+4i");
261    /// ```
262    #[inline]
263    fn div_exact(self, other: GaussianInteger) -> GaussianInteger {
264        div_exact_ref_ref(self, &other)
265    }
266}
267
268impl DivExact<&GaussianInteger> for &GaussianInteger {
269    type Output = GaussianInteger;
270
271    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`], taking both by reference. The
272    /// first [`GaussianInteger`] must be exactly divisible by the second. If it isn't, this
273    /// function may panic or return a meaningless result.
274    ///
275    /// $$
276    /// f(x, y) = \frac{x}{y}.
277    /// $$
278    ///
279    /// # Worst-case complexity
280    /// $T(n) = O(n \log n \log\log n)$
281    ///
282    /// $M(n) = O(n \log n)$
283    ///
284    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
285    /// bits of the real and imaginary parts of `self` and `other`.
286    ///
287    /// # Panics
288    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
289    ///
290    /// # Examples
291    /// ```
292    /// use malachite_base::num::arithmetic::traits::DivExact;
293    /// use malachite_nz::gaussian_integer::GaussianInteger;
294    /// use std::str::FromStr;
295    ///
296    /// // (3+4i)(5-2i) = 23+14i
297    /// let x = GaussianInteger::from_str("23+14i").unwrap();
298    /// let y = GaussianInteger::from_str("5-2i").unwrap();
299    /// assert_eq!(((&x).div_exact(&y)).to_string(), "3+4i");
300    /// ```
301    #[inline]
302    fn div_exact(self, other: &GaussianInteger) -> GaussianInteger {
303        div_exact_ref_ref(self, other)
304    }
305}
306
307impl DivExactAssign<Self> for GaussianInteger {
308    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`] in place, taking the
309    /// [`GaussianInteger`] on the right-hand side by value. The first [`GaussianInteger`] must be
310    /// exactly divisible by the second. If it isn't, this function may panic or return a
311    /// meaningless result.
312    ///
313    /// $$
314    /// f(x, y) = \frac{x}{y}.
315    /// $$
316    ///
317    /// # Worst-case complexity
318    /// $T(n) = O(n \log n \log\log n)$
319    ///
320    /// $M(n) = O(n \log n)$
321    ///
322    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
323    /// bits of the real and imaginary parts of `self` and `other`.
324    ///
325    /// # Panics
326    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
327    ///
328    /// # Examples
329    /// ```
330    /// use malachite_base::num::arithmetic::traits::DivExactAssign;
331    /// use malachite_nz::gaussian_integer::GaussianInteger;
332    /// use std::str::FromStr;
333    ///
334    /// // (3+4i)(5-2i) = 23+14i
335    /// let mut x = GaussianInteger::from_str("23+14i").unwrap();
336    /// x.div_exact_assign(GaussianInteger::from_str("5-2i").unwrap());
337    /// assert_eq!(x.to_string(), "3+4i");
338    /// ```
339    #[inline]
340    fn div_exact_assign(&mut self, other: Self) {
341        *self = div_exact_val_ref(take(self), &other);
342    }
343}
344
345impl DivExactAssign<&Self> for GaussianInteger {
346    /// Divides a [`GaussianInteger`] by another [`GaussianInteger`] in place, taking the
347    /// [`GaussianInteger`] on the right-hand side by reference. The first [`GaussianInteger`] must
348    /// be exactly divisible by the second. If it isn't, this function may panic or return a
349    /// meaningless result.
350    ///
351    /// $$
352    /// f(x, y) = \frac{x}{y}.
353    /// $$
354    ///
355    /// # Worst-case complexity
356    /// $T(n) = O(n \log n \log\log n)$
357    ///
358    /// $M(n) = O(n \log n)$
359    ///
360    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
361    /// bits of the real and imaginary parts of `self` and `other`.
362    ///
363    /// # Panics
364    /// Panics if `other` is zero. May panic if `self` is not divisible by `other`.
365    ///
366    /// # Examples
367    /// ```
368    /// use malachite_base::num::arithmetic::traits::DivExactAssign;
369    /// use malachite_nz::gaussian_integer::GaussianInteger;
370    /// use std::str::FromStr;
371    ///
372    /// // (3+4i)(5-2i) = 23+14i
373    /// let mut x = GaussianInteger::from_str("23+14i").unwrap();
374    /// x.div_exact_assign(&GaussianInteger::from_str("5-2i").unwrap());
375    /// assert_eq!(x.to_string(), "3+4i");
376    /// ```
377    #[inline]
378    fn div_exact_assign(&mut self, other: &Self) {
379        *self = div_exact_val_ref(take(self), other);
380    }
381}