1use crate::Float;
18#[cfg(feature = "integer")]
19use crate::Integer;
20#[cfg(feature = "rational")]
21use crate::Rational;
22use crate::ext::xmpfr;
23#[allow(deprecated)]
24use crate::float::SmallFloat;
25use crate::float::big::{IExpIncomplete, UExpIncomplete};
26use crate::float::{MiniFloat, Special};
27use az::Cast;
28use core::cmp::Ordering;
29
30impl PartialEq for Float {
31 #[inline]
32 fn eq(&self, other: &Float) -> bool {
33 xmpfr::equal_p(self, other)
34 }
35}
36
37impl PartialOrd for Float {
38 #[inline]
39 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
40 if xmpfr::unordered_p(self, other) {
41 None
42 } else {
43 Some(xmpfr::cmp(self, other))
44 }
45 }
46
47 #[inline]
48 fn lt(&self, other: &Float) -> bool {
49 xmpfr::less_p(self, other)
50 }
51
52 #[inline]
53 fn le(&self, other: &Float) -> bool {
54 xmpfr::lessequal_p(self, other)
55 }
56
57 #[inline]
58 fn gt(&self, other: &Float) -> bool {
59 xmpfr::greater_p(self, other)
60 }
61
62 #[inline]
63 fn ge(&self, other: &Float) -> bool {
64 xmpfr::greaterequal_p(self, other)
65 }
66}
67
68impl PartialOrd<MiniFloat> for Float {
69 #[inline]
70 fn partial_cmp(&self, other: &MiniFloat) -> Option<Ordering> {
71 self.partial_cmp(&*other.borrow())
72 }
73}
74
75impl PartialOrd<Float> for MiniFloat {
76 #[inline]
77 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
78 (*self.borrow()).partial_cmp(other)
79 }
80}
81
82impl PartialEq<MiniFloat> for Float {
83 #[inline]
84 fn eq(&self, other: &MiniFloat) -> bool {
85 self.eq(&*other.borrow())
86 }
87}
88
89impl PartialEq<Float> for MiniFloat {
90 #[inline]
91 fn eq(&self, other: &Float) -> bool {
92 (*self.borrow()).eq(other)
93 }
94}
95
96#[allow(deprecated)]
97impl PartialOrd<SmallFloat> for Float {
98 #[inline]
99 fn partial_cmp(&self, other: &SmallFloat) -> Option<Ordering> {
100 self.partial_cmp(&**other)
101 }
102}
103
104#[allow(deprecated)]
105impl PartialOrd<Float> for SmallFloat {
106 #[inline]
107 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
108 (**self).partial_cmp(other)
109 }
110}
111
112#[allow(deprecated)]
113impl PartialEq<SmallFloat> for Float {
114 #[inline]
115 fn eq(&self, other: &SmallFloat) -> bool {
116 self.eq(&**other)
117 }
118}
119
120#[allow(deprecated)]
121impl PartialEq<Float> for SmallFloat {
122 #[inline]
123 fn eq(&self, other: &Float) -> bool {
124 (**self).eq(other)
125 }
126}
127
128macro_rules! cmp {
129 ($T:ty) => {
130 impl PartialEq<$T> for Float {
131 #[inline]
132 fn eq(&self, other: &$T) -> bool {
133 self.partial_cmp(other) == Some(Ordering::Equal)
134 }
135 }
136
137 impl PartialEq<Float> for $T {
138 #[inline]
139 fn eq(&self, other: &Float) -> bool {
140 other.partial_cmp(self) == Some(Ordering::Equal)
141 }
142 }
143
144 impl PartialOrd<Float> for $T {
145 #[inline]
146 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
147 other.partial_cmp(self).map(Ordering::reverse)
148 }
149 }
150 };
151}
152
153macro_rules! cmp_i {
154 ($T:ty, |$f:ident, $o:ident| $eval:expr) => {
155 cmp! { $T }
156
157 impl PartialOrd<$T> for Float {
158 #[inline]
159 fn partial_cmp(&self, $o: &$T) -> Option<Ordering> {
160 if self.is_nan() {
161 None
162 } else {
163 let $f = self;
164 Some($eval)
165 }
166 }
167 }
168 };
169}
170
171macro_rules! cmp_f {
172 ($T:ty, |$f:ident, $o:ident| $eval:expr) => {
173 cmp! { $T }
174
175 impl PartialOrd<$T> for Float {
176 #[inline]
177 fn partial_cmp(&self, $o: &$T) -> Option<Ordering> {
178 if self.is_nan() || $o.is_nan() {
179 None
180 } else {
181 let $f = self;
182 Some($eval)
183 }
184 }
185 }
186 };
187}
188
189#[cfg(feature = "integer")]
190cmp_i! { Integer, |f, z| xmpfr::cmp_z(f, z) }
191#[cfg(feature = "rational")]
192cmp_i! { Rational, |f, q| xmpfr::cmp_q(f, q) }
193
194cmp_i! { i8, |f, t| xmpfr::cmp_si(f, (*t).into()) }
195cmp_i! { i16, |f, t| xmpfr::cmp_si(f, (*t).into()) }
196cmp_i! { i32, |f, t| xmpfr::cmp_si(f, (*t).into()) }
197cmp_i! { i64, |f, t| xmpfr::cmp_i64(f, *t) }
198cmp_i! { i128, |f, t| xmpfr::cmp_i128(f, *t) }
199#[cfg(target_pointer_width = "32")]
200cmp_i! { isize, |f, t| xmpfr::cmp_si(f, (*t).cast()) }
201#[cfg(target_pointer_width = "64")]
202cmp_i! { isize, |f, t| xmpfr::cmp_i64(f, (*t).cast()) }
203
204cmp_i! { u8, |f, t| xmpfr::cmp_ui(f, (*t).into()) }
205cmp_i! { u16, |f, t| xmpfr::cmp_ui(f, (*t).into()) }
206cmp_i! { u32, |f, t| xmpfr::cmp_ui(f, (*t).into()) }
207cmp_i! { u64, |f, t| xmpfr::cmp_u64(f, *t) }
208cmp_i! { u128, |f, t| xmpfr::cmp_u128(f, *t) }
209#[cfg(target_pointer_width = "32")]
210cmp_i! { usize, |f, t| xmpfr::cmp_ui(f, (*t).cast()) }
211#[cfg(target_pointer_width = "64")]
212cmp_i! { usize, |f, t| xmpfr::cmp_u64(f, (*t).cast()) }
213
214#[cfg(feature = "nightly-float")]
215cmp_f! { f16, |f, t| xmpfr::cmp_f64(f, (*t).into()) }
216cmp_f! { f32, |f, t| xmpfr::cmp_f64(f, (*t).into()) }
217cmp_f! { f64, |f, t| xmpfr::cmp_f64(f, *t) }
218
219#[cfg(feature = "nightly-float")]
220cmp! { f128 }
221
222#[cfg(feature = "nightly-float")]
223impl PartialOrd<f128> for Float {
224 #[inline]
225 fn partial_cmp(&self, o: &f128) -> Option<Ordering> {
226 let mut small = MiniFloat::from(*o);
227 PartialOrd::partial_cmp(self, small.borrow_excl())
228 }
229}
230
231cmp! { Special }
232
233impl PartialOrd<Special> for Float {
234 #[inline]
235 fn partial_cmp(&self, other: &Special) -> Option<Ordering> {
236 if self.is_nan() {
237 return None;
238 }
239 match *other {
240 Special::Zero | Special::NegZero => self.cmp0(),
241 Special::Infinity => {
242 if self.is_sign_positive() && self.is_infinite() {
243 Some(Ordering::Equal)
244 } else {
245 Some(Ordering::Less)
246 }
247 }
248 Special::NegInfinity => {
249 if self.is_sign_negative() && self.is_infinite() {
250 Some(Ordering::Equal)
251 } else {
252 Some(Ordering::Greater)
253 }
254 }
255 Special::Nan => None,
256 }
257 }
258}
259
260cmp! { UExpIncomplete }
261cmp! { IExpIncomplete }
262
263#[cfg(test)]
264mod tests {
265 #[cfg(feature = "integer")]
266 use crate::Integer;
267 #[cfg(feature = "rational")]
268 use crate::Rational;
269 use crate::float;
270 use crate::float::{FreeCache, Special};
271 use crate::{Assign, Float};
272 use core::cmp::Ordering;
273 #[cfg(feature = "integer")]
274 use core::str::FromStr;
275
276 fn check_cmp_prim<T>(s: &[T], against: &[Float])
277 where
278 Float: Assign<T> + PartialEq<T> + PartialOrd<T>,
279 T: Copy + PartialEq<Float> + PartialOrd<Float>,
280 {
281 for op in s {
282 let fop = Float::with_val(150, *op);
283 for b in against {
284 assert_eq!(b.eq(op), PartialEq::<Float>::eq(b, &fop));
285 assert_eq!(op.eq(b), PartialEq::<Float>::eq(&fop, b));
286 assert_eq!(b.eq(op), op.eq(b));
287 assert_eq!(b.partial_cmp(op), PartialOrd::<Float>::partial_cmp(b, &fop));
288 assert_eq!(op.partial_cmp(b), PartialOrd::<Float>::partial_cmp(&fop, b));
289 assert_eq!(b.partial_cmp(op), op.partial_cmp(b).map(Ordering::reverse));
290 }
291 }
292 }
293
294 #[cfg(feature = "integer")]
295 fn check_cmp_big<'a, T>(s: &'a [T], against: &[Float])
296 where
297 Float: Assign<&'a T> + PartialEq<T> + PartialOrd<T>,
298 T: PartialEq<Float> + PartialOrd<Float>,
299 {
300 for op in s {
301 let fop = Float::with_val(150, op);
302 for b in against {
303 assert_eq!(b.eq(op), PartialEq::<Float>::eq(b, &fop));
304 assert_eq!(op.eq(b), PartialEq::<Float>::eq(&fop, b));
305 assert_eq!(b.eq(op), op.eq(b));
306 assert_eq!(b.partial_cmp(op), PartialOrd::<Float>::partial_cmp(b, &fop));
307 assert_eq!(op.partial_cmp(b), PartialOrd::<Float>::partial_cmp(&fop, b));
308 assert_eq!(b.partial_cmp(op), op.partial_cmp(b).map(Ordering::reverse));
309 }
310 }
311 }
312
313 #[test]
314 fn check_cmp_others() {
315 use crate::tests::{F32, F64, I32, I64, I128, U32, U64, U128};
316 let large = [
317 Float::with_val(20, Special::Zero),
318 Float::with_val(20, Special::NegZero),
319 Float::with_val(20, Special::Infinity),
320 Float::with_val(20, Special::NegInfinity),
321 Float::with_val(20, Special::Nan),
322 Float::with_val(20, 1),
323 Float::with_val(20, -1),
324 Float::with_val(20, 999_999e100),
325 Float::with_val(20, 999_999e-100),
326 Float::with_val(20, -999_999e100),
327 Float::with_val(20, -999_999e-100),
328 ];
329 #[cfg(feature = "integer")]
330 let z = &[
331 Integer::from(0),
332 Integer::from(1),
333 Integer::from(-1),
334 Integer::from_str("-1000000000000").unwrap(),
335 Integer::from_str("1000000000000").unwrap(),
336 ];
337 #[cfg(feature = "rational")]
338 let q = &[
339 Rational::from(0),
340 Rational::from(1),
341 Rational::from(-1),
342 Rational::from_str("-1000000000000/33333333333").unwrap(),
343 Rational::from_str("1000000000000/33333333333").unwrap(),
344 ];
345
346 let against = large
347 .iter()
348 .cloned()
349 .chain(U32.iter().map(|&x| Float::with_val(20, x)))
350 .chain(I32.iter().map(|&x| Float::with_val(20, x)))
351 .chain(U64.iter().map(|&x| Float::with_val(20, x)))
352 .chain(I64.iter().map(|&x| Float::with_val(20, x)))
353 .chain(U128.iter().map(|&x| Float::with_val(20, x)))
354 .chain(I128.iter().map(|&x| Float::with_val(20, x)))
355 .chain(F32.iter().map(|&x| Float::with_val(20, x)))
356 .chain(F64.iter().map(|&x| Float::with_val(20, x)))
357 .collect::<Vec<Float>>();
358 #[cfg(feature = "integer")]
359 let mut against = against;
360 #[cfg(feature = "integer")]
361 against.extend(z.iter().map(|x| Float::with_val(20, x)));
362 #[cfg(feature = "rational")]
363 against.extend(q.iter().map(|x| Float::with_val(20, x)));
364 check_cmp_prim(U32, &against);
365 check_cmp_prim(I32, &against);
366 check_cmp_prim(U64, &against);
367 check_cmp_prim(I64, &against);
368 check_cmp_prim(U128, &against);
369 check_cmp_prim(I128, &against);
370 check_cmp_prim(F32, &against);
371 check_cmp_prim(F64, &against);
372 #[cfg(feature = "integer")]
373 check_cmp_big(z, &against);
374 #[cfg(feature = "rational")]
375 check_cmp_big(q, &against);
376
377 float::free_cache(FreeCache::All);
378 }
379}