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}