Skip to main content

malachite_nz/gaussian_integer/arithmetic/
content_and_primitive_part.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::gaussian_integer::GaussianInteger;
10use crate::integer::Integer;
11use crate::natural::Natural;
12use malachite_base::num::arithmetic::traits::{
13    Content, ContentAndPrimitivePart, DivExact, Gcd, PrimitivePart, UnsignedAbs,
14};
15use malachite_base::num::basic::traits::Zero;
16
17fn content_and_primitive_part_val(x: GaussianInteger) -> (Natural, GaussianInteger) {
18    let g = x
19        .real
20        .unsigned_abs_ref()
21        .gcd(x.imaginary.unsigned_abs_ref());
22    if g == 0u32 {
23        (Natural::ZERO, GaussianInteger::ZERO)
24    } else if g == 1u32 {
25        (g, x)
26    } else {
27        let g_int = Integer::from(&g);
28        let primitive = GaussianInteger {
29            real: x.real.div_exact(&g_int),
30            imaginary: x.imaginary.div_exact(g_int),
31        };
32        (g, primitive)
33    }
34}
35
36fn content_and_primitive_part_ref(x: &GaussianInteger) -> (Natural, GaussianInteger) {
37    let g = x
38        .real
39        .unsigned_abs_ref()
40        .gcd(x.imaginary.unsigned_abs_ref());
41    if g == 0u32 {
42        (Natural::ZERO, GaussianInteger::ZERO)
43    } else if g == 1u32 {
44        (g, x.clone())
45    } else {
46        let g_int = Integer::from(&g);
47        let primitive = GaussianInteger {
48            real: (&x.real).div_exact(&g_int),
49            imaginary: (&x.imaginary).div_exact(g_int),
50        };
51        (g, primitive)
52    }
53}
54
55impl ContentAndPrimitivePart for GaussianInteger {
56    type Content = Natural;
57    type PrimitivePart = Self;
58
59    /// Splits a [`GaussianInteger`] into its content and its primitive part, taking the
60    /// [`GaussianInteger`] by value.
61    ///
62    /// The content of a Gaussian integer is the GCD of its real and imaginary parts, a non-negative
63    /// integer, and the primitive part is the Gaussian integer with coprime parts that remains
64    /// after dividing it out; their product is the original number. Zero has content 0 and
65    /// primitive part 0, and the unit of a nonzero number stays in its primitive part.
66    ///
67    /// $$
68    /// f(a + bi) = \left ( g, \frac{a}{g} + \frac{b}{g} i \right ), \quad
69    /// \text{where } g = \gcd(|a|, |b|).
70    /// $$
71    ///
72    /// # Worst-case complexity
73    /// $T(n) = O(n (\log n)^2 \log\log n)$
74    ///
75    /// $M(n) = O(n \log n)$
76    ///
77    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
78    /// bits of the real and imaginary parts of `self`.
79    ///
80    /// # Examples
81    /// ```
82    /// use malachite_base::num::arithmetic::traits::ContentAndPrimitivePart;
83    /// use malachite_nz::gaussian_integer::GaussianInteger;
84    /// use std::str::FromStr;
85    ///
86    /// let (content, primitive) = GaussianInteger::from_str("-6+9i")
87    ///     .unwrap()
88    ///     .content_and_primitive_part();
89    /// assert_eq!(content, 3);
90    /// assert_eq!(primitive.to_string(), "-2+3i");
91    /// ```
92    #[inline]
93    fn content_and_primitive_part(self) -> (Natural, Self) {
94        content_and_primitive_part_val(self)
95    }
96}
97
98impl ContentAndPrimitivePart for &GaussianInteger {
99    type Content = Natural;
100    type PrimitivePart = GaussianInteger;
101
102    /// Splits a [`GaussianInteger`] into its content and its primitive part, taking the
103    /// [`GaussianInteger`] by reference.
104    ///
105    /// The content of a Gaussian integer is the GCD of its real and imaginary parts, a non-negative
106    /// integer, and the primitive part is the Gaussian integer with coprime parts that remains
107    /// after dividing it out; their product is the original number. Zero has content 0 and
108    /// primitive part 0, and the unit of a nonzero number stays in its primitive part.
109    ///
110    /// $$
111    /// f(a + bi) = \left ( g, \frac{a}{g} + \frac{b}{g} i \right ), \quad
112    /// \text{where } g = \gcd(|a|, |b|).
113    /// $$
114    ///
115    /// # Worst-case complexity
116    /// $T(n) = O(n (\log n)^2 \log\log n)$
117    ///
118    /// $M(n) = O(n \log n)$
119    ///
120    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
121    /// bits of the real and imaginary parts of `self`.
122    ///
123    /// # Examples
124    /// ```
125    /// use malachite_base::num::arithmetic::traits::ContentAndPrimitivePart;
126    /// use malachite_nz::gaussian_integer::GaussianInteger;
127    /// use std::str::FromStr;
128    ///
129    /// let x = GaussianInteger::from_str("-6+9i").unwrap();
130    /// let (content, primitive) = (&x).content_and_primitive_part();
131    /// assert_eq!(content, 3);
132    /// assert_eq!(primitive.to_string(), "-2+3i");
133    /// ```
134    #[inline]
135    fn content_and_primitive_part(self) -> (Natural, GaussianInteger) {
136        content_and_primitive_part_ref(self)
137    }
138}
139
140impl Content for GaussianInteger {
141    type Output = Natural;
142
143    /// Computes the content of a [`GaussianInteger`], the GCD of its real and imaginary parts,
144    /// taking the [`GaussianInteger`] by value.
145    ///
146    /// $$
147    /// f(a + bi) = \gcd(|a|, |b|).
148    /// $$
149    ///
150    /// # Worst-case complexity
151    /// $T(n) = O(n (\log n)^2 \log\log n)$
152    ///
153    /// $M(n) = O(n \log n)$
154    ///
155    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
156    /// bits of the real and imaginary parts of `self`.
157    ///
158    /// # Examples
159    /// ```
160    /// use malachite_base::num::arithmetic::traits::Content;
161    /// use malachite_nz::gaussian_integer::GaussianInteger;
162    /// use std::str::FromStr;
163    ///
164    /// assert_eq!(GaussianInteger::from_str("-6+9i").unwrap().content(), 3);
165    /// assert_eq!(GaussianInteger::from_str("7+11i").unwrap().content(), 1);
166    /// ```
167    #[inline]
168    fn content(self) -> Natural {
169        self.real.unsigned_abs().gcd(self.imaginary.unsigned_abs())
170    }
171}
172
173impl Content for &GaussianInteger {
174    type Output = Natural;
175
176    /// Computes the content of a [`GaussianInteger`], the GCD of its real and imaginary parts,
177    /// taking the [`GaussianInteger`] by reference.
178    ///
179    /// $$
180    /// f(a + bi) = \gcd(|a|, |b|).
181    /// $$
182    ///
183    /// # Worst-case complexity
184    /// $T(n) = O(n (\log n)^2 \log\log n)$
185    ///
186    /// $M(n) = O(n \log n)$
187    ///
188    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
189    /// bits of the real and imaginary parts of `self`.
190    ///
191    /// # Examples
192    /// ```
193    /// use malachite_base::num::arithmetic::traits::Content;
194    /// use malachite_nz::gaussian_integer::GaussianInteger;
195    /// use std::str::FromStr;
196    ///
197    /// assert_eq!((&GaussianInteger::from_str("-6+9i").unwrap()).content(), 3);
198    /// assert_eq!((&GaussianInteger::from_str("7+11i").unwrap()).content(), 1);
199    /// ```
200    #[inline]
201    fn content(self) -> Natural {
202        self.real
203            .unsigned_abs_ref()
204            .gcd(self.imaginary.unsigned_abs_ref())
205    }
206}
207
208impl PrimitivePart for GaussianInteger {
209    type Output = Self;
210
211    /// Computes the primitive part of a [`GaussianInteger`], the [`GaussianInteger`] with coprime
212    /// parts that remains after dividing out the content, taking the [`GaussianInteger`] by value.
213    ///
214    /// $$
215    /// f(a + bi) = \frac{a}{g} + \frac{b}{g} i, \quad \text{where } g = \gcd(|a|, |b|).
216    /// $$
217    ///
218    /// # Worst-case complexity
219    /// $T(n) = O(n (\log n)^2 \log\log n)$
220    ///
221    /// $M(n) = O(n \log n)$
222    ///
223    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
224    /// bits of the real and imaginary parts of `self`.
225    ///
226    /// # Examples
227    /// ```
228    /// use malachite_base::num::arithmetic::traits::PrimitivePart;
229    /// use malachite_nz::gaussian_integer::GaussianInteger;
230    /// use std::str::FromStr;
231    ///
232    /// assert_eq!(
233    ///     GaussianInteger::from_str("-6+9i")
234    ///         .unwrap()
235    ///         .primitive_part()
236    ///         .to_string(),
237    ///     "-2+3i"
238    /// );
239    /// ```
240    #[inline]
241    fn primitive_part(self) -> Self {
242        content_and_primitive_part_val(self).1
243    }
244}
245
246impl PrimitivePart for &GaussianInteger {
247    type Output = GaussianInteger;
248
249    /// Computes the primitive part of a [`GaussianInteger`], the [`GaussianInteger`] with coprime
250    /// parts that remains after dividing out the content, taking the [`GaussianInteger`] by
251    /// reference.
252    ///
253    /// $$
254    /// f(a + bi) = \frac{a}{g} + \frac{b}{g} i, \quad \text{where } g = \gcd(|a|, |b|).
255    /// $$
256    ///
257    /// # Worst-case complexity
258    /// $T(n) = O(n (\log n)^2 \log\log n)$
259    ///
260    /// $M(n) = O(n \log n)$
261    ///
262    /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of significant
263    /// bits of the real and imaginary parts of `self`.
264    ///
265    /// # Examples
266    /// ```
267    /// use malachite_base::num::arithmetic::traits::PrimitivePart;
268    /// use malachite_nz::gaussian_integer::GaussianInteger;
269    /// use std::str::FromStr;
270    ///
271    /// assert_eq!(
272    ///     (&GaussianInteger::from_str("-6+9i").unwrap())
273    ///         .primitive_part()
274    ///         .to_string(),
275    ///     "-2+3i"
276    /// );
277    /// ```
278    #[inline]
279    fn primitive_part(self) -> GaussianInteger {
280        content_and_primitive_part_ref(self).1
281    }
282}