Skip to main content

rug/complex/
cmp.rs

1// Copyright © 2016–2026 Trevor Spiteri
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17#[cfg(feature = "integer")]
18use crate::Integer;
19#[cfg(feature = "rational")]
20use crate::Rational;
21use crate::complex::MiniComplex;
22#[allow(deprecated)]
23use crate::complex::SmallComplex;
24use crate::float::Special;
25use crate::{Complex, Float};
26
27impl PartialEq for Complex {
28    #[inline]
29    fn eq(&self, other: &Complex) -> bool {
30        self.real().eq(other.real()) && self.imag().eq(other.imag())
31    }
32}
33
34impl PartialEq<MiniComplex> for Complex {
35    #[inline]
36    fn eq(&self, other: &MiniComplex) -> bool {
37        self.eq(&*other.borrow())
38    }
39}
40
41impl PartialEq<Complex> for MiniComplex {
42    #[inline]
43    fn eq(&self, other: &Complex) -> bool {
44        (*self.borrow()).eq(other)
45    }
46}
47
48#[allow(deprecated)]
49impl PartialEq<SmallComplex> for Complex {
50    #[inline]
51    fn eq(&self, other: &SmallComplex) -> bool {
52        self.eq(&**other)
53    }
54}
55
56#[allow(deprecated)]
57impl PartialEq<Complex> for SmallComplex {
58    #[inline]
59    fn eq(&self, other: &Complex) -> bool {
60        (**self).eq(other)
61    }
62}
63
64macro_rules! eq_re_im {
65    ($Re:ty; $($Im:ty)*) => { $(
66        impl PartialEq<($Re, $Im)> for Complex {
67            #[inline]
68            fn eq(&self, other: &($Re, $Im)) -> bool {
69                self.real().eq(&other.0) && self.imag().eq(&other.1)
70            }
71        }
72
73        impl PartialEq<Complex> for ($Re, $Im) {
74            #[inline]
75            fn eq(&self, other: &Complex) -> bool {
76                other.real().eq(&self.0) && other.imag().eq(&self.1)
77            }
78        }
79    )* };
80}
81
82macro_rules! eq_re {
83    ($($Re:ty)*) => { $(
84        impl PartialEq<$Re> for Complex {
85            #[inline]
86            fn eq(&self, other: &$Re) -> bool {
87                self.imag().is_zero() && self.real().eq(other)
88            }
89        }
90
91        impl PartialEq<Complex> for $Re {
92            #[inline]
93            fn eq(&self, other: &Complex) -> bool {
94                other.imag().is_zero() && other.real().eq(self)
95            }
96        }
97
98        #[cfg(feature = "integer")]
99        eq_re_im! { $Re; Integer }
100        #[cfg(feature = "rational")]
101        eq_re_im! { $Re; Rational }
102        eq_re_im! { $Re; Float Special }
103        eq_re_im! { $Re; i8 i16 i32 i64 i128 isize }
104        eq_re_im! { $Re; u8 u16 u32 u64 u128 usize }
105        eq_re_im! { $Re; f32 f64 }
106        #[cfg(feature = "nightly-float")]
107        eq_re_im! { $Re; f16 f128 }
108    )* };
109}
110
111#[cfg(feature = "integer")]
112eq_re! { Integer }
113#[cfg(feature = "rational")]
114eq_re! { Rational }
115eq_re! { Float Special }
116eq_re! { i8 i16 i32 i64 i128 isize }
117eq_re! { u8 u16 u32 u64 u128 usize }
118eq_re! { f32 f64 }
119#[cfg(feature = "nightly-float")]
120eq_re! { f16 f128 }
121
122#[cfg(test)]
123mod tests {
124    #[cfg(feature = "integer")]
125    use crate::Integer;
126    #[cfg(feature = "rational")]
127    use crate::Rational;
128    use crate::float;
129    use crate::float::{FreeCache, Special};
130    use crate::{Assign, Complex, Float};
131    #[cfg(feature = "integer")]
132    use core::str::FromStr;
133
134    fn check_eq_prim<T>(s: &[T], against: &[Complex])
135    where
136        Complex: Assign<T> + Assign<(T, T)> + PartialEq<T> + PartialEq<(T, T)>,
137        T: Copy + PartialEq<Complex>,
138        (T, T): Copy + PartialEq<Complex>,
139    {
140        for op in s {
141            let fop = Complex::with_val(150, *op);
142            for b in against {
143                assert_eq!(b.eq(op), b.eq(&fop));
144                assert_eq!(op.eq(b), fop.eq(b));
145                assert_eq!(b.eq(op), op.eq(b));
146            }
147        }
148        for op in combinations(s) {
149            let fop = Complex::with_val(150, op);
150            for b in against {
151                assert_eq!(b.eq(&op), b.eq(&fop));
152                assert_eq!(op.eq(b), fop.eq(b));
153                assert_eq!(b.eq(&op), op.eq(b));
154            }
155        }
156    }
157
158    fn check_eq_big<'a, T>(s: &'a [T], against: &[Complex])
159    where
160        Complex:
161            for<'b> Assign<&'b T> + for<'b> Assign<&'b (T, T)> + PartialEq<T> + PartialEq<(T, T)>,
162        T: Clone + PartialEq<Complex>,
163        (T, T): Clone + PartialEq<Complex>,
164    {
165        for op in s {
166            let fop = Complex::with_val(150, op);
167            for b in against {
168                assert_eq!(b.eq(op), b.eq(&fop));
169                assert_eq!(op.eq(b), fop.eq(b));
170                assert_eq!(b.eq(op), op.eq(b));
171            }
172        }
173        for op in combinations(s) {
174            let fop = Complex::with_val(150, &op);
175            for b in against {
176                assert_eq!(b.eq(&op), b.eq(&fop));
177                assert_eq!(op.eq(b), fop.eq(b));
178                assert_eq!(b.eq(&op), op.eq(b));
179            }
180        }
181    }
182
183    fn combinations<T: Clone>(t: &[T]) -> Vec<(T, T)> {
184        let mut ret = Vec::with_capacity(t.len() * t.len());
185        for re in t {
186            for im in t {
187                ret.push((re.clone(), im.clone()));
188            }
189        }
190        ret
191    }
192
193    fn to_complex<T>(t: T) -> Complex
194    where
195        Complex: Assign<T>,
196    {
197        Complex::with_val(20, t)
198    }
199
200    #[test]
201    fn check_eq_others() {
202        use crate::tests::{F32, F64, I32, I64, I128, U32, U64, U128};
203        #[cfg(feature = "integer")]
204        let z = [
205            Integer::from(0),
206            Integer::from(1),
207            Integer::from(-1),
208            Integer::from_str("-1000000000000").unwrap(),
209            Integer::from_str("1000000000000").unwrap(),
210        ];
211        #[cfg(feature = "rational")]
212        let q = [
213            Rational::from(0),
214            Rational::from(1),
215            Rational::from(-1),
216            Rational::from_str("-1000000000000/33333333333").unwrap(),
217            Rational::from_str("1000000000000/33333333333").unwrap(),
218        ];
219        let f = [
220            Float::with_val(20, Special::Zero),
221            Float::with_val(20, Special::NegZero),
222            Float::with_val(20, Special::Infinity),
223            Float::with_val(20, Special::NegInfinity),
224            Float::with_val(20, Special::Nan),
225            Float::with_val(20, 1),
226            Float::with_val(20, -1),
227            Float::with_val(20, 999_999e100),
228            Float::with_val(20, 999_999e-100),
229            Float::with_val(20, -999_999e100),
230            Float::with_val(20, -999_999e-100),
231        ];
232
233        let against = combinations(&f)
234            .iter()
235            .map(to_complex)
236            .chain(combinations(U32).iter().map(to_complex))
237            .chain(combinations(I32).iter().map(to_complex))
238            .chain(combinations(U64).iter().map(to_complex))
239            .chain(combinations(I64).iter().map(to_complex))
240            .chain(combinations(U128).iter().map(to_complex))
241            .chain(combinations(I128).iter().map(to_complex))
242            .chain(combinations(F32).iter().map(to_complex))
243            .chain(combinations(F64).iter().map(to_complex))
244            .collect::<Vec<Complex>>();
245        #[cfg(feature = "integer")]
246        let mut against = against;
247        #[cfg(feature = "integer")]
248        against.extend(combinations(&z).iter().map(to_complex));
249        #[cfg(feature = "rational")]
250        against.extend(combinations(&q).iter().map(to_complex));
251        check_eq_prim(U32, &against);
252        check_eq_prim(I32, &against);
253        check_eq_prim(U64, &against);
254        check_eq_prim(I64, &against);
255        check_eq_prim(U128, &against);
256        check_eq_prim(I128, &against);
257        check_eq_prim(F32, &against);
258        check_eq_prim(F64, &against);
259        #[cfg(feature = "integer")]
260        check_eq_big(&z, &against);
261        #[cfg(feature = "rational")]
262        check_eq_big(&q, &against);
263        check_eq_big(&f, &against);
264
265        float::free_cache(FreeCache::All);
266    }
267}