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}