malachite_q/comparison/partial_cmp_primitive_float.rs
1// Copyright © 2025 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::Rational;
10use core::cmp::Ordering::{self, *};
11use malachite_base::num::arithmetic::traits::FloorLogBase2;
12
13macro_rules! impl_float {
14 ($t: ident) => {
15 impl PartialOrd<$t> for Rational {
16 /// Compares a [`Rational`] to a primitive float.
17 ///
18 /// # Worst-case complexity
19 /// $T(n) = O(n \log n \log\log n)$
20 ///
21 /// $M(n) = O(n \log n)$
22 ///
23 /// where $T$ is time, $M$ is additional memory, and $n$ is
24 /// `max(self.significant_bits(), other.sci_exponent().abs())`.
25 ///
26 /// # Examples
27 /// See [here](super::partial_cmp_primitive_float#partial_cmp).
28 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
29 if other.is_nan() {
30 None
31 } else if self.sign != (*other >= 0.0) {
32 Some(if self.sign { Greater } else { Less })
33 } else if !other.is_finite() {
34 Some(if self.sign { Less } else { Greater })
35 } else if *other == 0.0 {
36 self.partial_cmp(&0u32)
37 } else if *self == 0u32 {
38 0.0.partial_cmp(other)
39 } else {
40 let ord_cmp = self
41 .floor_log_base_2_abs()
42 .cmp(&other.abs().floor_log_base_2());
43 Some(if ord_cmp != Equal {
44 if self.sign {
45 ord_cmp
46 } else {
47 ord_cmp.reverse()
48 }
49 } else {
50 self.cmp(&Rational::try_from(*other).unwrap())
51 })
52 }
53 }
54 }
55
56 impl PartialOrd<Rational> for $t {
57 /// Compares a primitive float to a [`Rational`].
58 ///
59 /// # Worst-case complexity
60 /// $T(n) = O(n \log n \log\log n)$
61 ///
62 /// $M(n) = O(n \log n)$
63 ///
64 /// where $T$ is time, $M$ is additional memory, and $n$ is
65 /// `max(other.sci_exponent().abs(), self.significant_bits())`.
66 ///
67 /// # Examples
68 /// See [here](super::partial_cmp_primitive_float#partial_cmp).
69 #[inline]
70 fn partial_cmp(&self, other: &Rational) -> Option<Ordering> {
71 other.partial_cmp(self).map(Ordering::reverse)
72 }
73 }
74 };
75}
76apply_to_primitive_floats!(impl_float);