fixed/
cmp.rs

1// Copyright © 2018–2025 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16#![allow(deprecated)]
17
18use crate::float_helper;
19use crate::int_helper;
20use crate::int_helper::IntFixed;
21use crate::types::extra::Unsigned;
22use crate::{
23    F128, F128Bits, FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32,
24    FixedU64, FixedU128,
25};
26use core::cmp::Ordering;
27use core::ops::{Shl, Shr};
28use half::{bf16 as half_bf16, f16 as half_f16};
29
30macro_rules! fixed_cmp_int {
31    ($Fixed:ident, $Int:ident) => {
32        impl<Frac: Unsigned> PartialEq<$Int> for $Fixed<Frac> {
33            #[inline]
34            fn eq(&self, rhs: &$Int) -> bool {
35                let fixed_rhs = IntFixed(*rhs).fixed();
36                PartialEq::eq(self, &fixed_rhs)
37            }
38        }
39
40        impl<Frac: Unsigned> PartialEq<$Fixed<Frac>> for $Int {
41            #[inline]
42            fn eq(&self, rhs: &$Fixed<Frac>) -> bool {
43                let fixed_lhs = IntFixed(*self).fixed();
44                PartialEq::eq(&fixed_lhs, rhs)
45            }
46        }
47
48        impl<Frac: Unsigned> PartialOrd<$Int> for $Fixed<Frac> {
49            #[inline]
50            fn partial_cmp(&self, rhs: &$Int) -> Option<Ordering> {
51                let fixed_rhs = IntFixed(*rhs).fixed();
52                PartialOrd::partial_cmp(self, &fixed_rhs)
53            }
54
55            #[inline]
56            fn lt(&self, rhs: &$Int) -> bool {
57                let fixed_rhs = IntFixed(*rhs).fixed();
58                PartialOrd::lt(self, &fixed_rhs)
59            }
60
61            #[inline]
62            fn le(&self, rhs: &$Int) -> bool {
63                let fixed_rhs = IntFixed(*rhs).fixed();
64                PartialOrd::le(self, &fixed_rhs)
65            }
66
67            #[inline]
68            fn gt(&self, rhs: &$Int) -> bool {
69                let fixed_rhs = IntFixed(*rhs).fixed();
70                PartialOrd::gt(self, &fixed_rhs)
71            }
72
73            #[inline]
74            fn ge(&self, rhs: &$Int) -> bool {
75                let fixed_rhs = IntFixed(*rhs).fixed();
76                PartialOrd::ge(self, &fixed_rhs)
77            }
78        }
79
80        impl<Frac: Unsigned> PartialOrd<$Fixed<Frac>> for $Int {
81            #[inline]
82            fn partial_cmp(&self, rhs: &$Fixed<Frac>) -> Option<Ordering> {
83                let fixed_lhs = IntFixed(*self).fixed();
84                PartialOrd::partial_cmp(&fixed_lhs, rhs)
85            }
86
87            #[inline]
88            fn lt(&self, rhs: &$Fixed<Frac>) -> bool {
89                let fixed_lhs = IntFixed(*self).fixed();
90                PartialOrd::lt(&fixed_lhs, rhs)
91            }
92
93            #[inline]
94            fn le(&self, rhs: &$Fixed<Frac>) -> bool {
95                let fixed_lhs = IntFixed(*self).fixed();
96                PartialOrd::le(&fixed_lhs, rhs)
97            }
98
99            #[inline]
100            fn gt(&self, rhs: &$Fixed<Frac>) -> bool {
101                let fixed_lhs = IntFixed(*self).fixed();
102                PartialOrd::gt(&fixed_lhs, rhs)
103            }
104
105            #[inline]
106            fn ge(&self, rhs: &$Fixed<Frac>) -> bool {
107                let fixed_lhs = IntFixed(*self).fixed();
108                PartialOrd::ge(&fixed_lhs, rhs)
109            }
110        }
111    };
112}
113
114// Zero must NOT be neg
115struct Value<U> {
116    neg: bool,
117    abs: U,
118    bits: u32,
119    frac_bits: i32,
120}
121
122#[inline]
123// lhs_frac >= rhs_frac
124fn float_rhs_shl<U>(rhs_abs: U, bits: u32, lhs_frac: i32, rhs_frac: i32) -> Option<U>
125where
126    U: Copy + Eq + TryFrom<u32> + Shl<u32, Output = U> + Shr<u32, Output = U>,
127{
128    debug_assert!(lhs_frac >= rhs_frac);
129    let rhs_shl = lhs_frac.wrapping_sub(rhs_frac) as u32;
130    let Ok(rhs_zero) = U::try_from(0u32) else {
131        unreachable!();
132    };
133    if rhs_abs == rhs_zero {
134        Some(rhs_zero)
135    } else if rhs_shl >= bits {
136        None
137    } else {
138        let shifted = rhs_abs << rhs_shl;
139        if (shifted >> rhs_shl) == rhs_abs {
140            Some(shifted)
141        } else {
142            None
143        }
144    }
145}
146
147#[inline]
148fn float_eq_even<U>(lhs: Value<U>, rhs: Value<U>) -> bool
149where
150    U: Copy + Eq + TryFrom<u32> + Shl<u32, Output = U> + Shr<u32, Output = U>,
151{
152    if lhs.frac_bits < rhs.frac_bits {
153        return float_eq_even(rhs, lhs);
154    }
155
156    if lhs.neg != rhs.neg {
157        return false;
158    }
159
160    // lhs.frac_bits >= rhs.frac_bits
161    match float_rhs_shl(rhs.abs, rhs.bits, lhs.frac_bits, rhs.frac_bits) {
162        None => false,
163        Some(shifted_rhs_abs) => lhs.abs == shifted_rhs_abs,
164    }
165}
166
167#[inline]
168fn float_eq<Lhs, Rhs>(lhs: Value<Lhs>, rhs: Value<Rhs>) -> bool
169where
170    Lhs: Copy + Eq + TryFrom<u32> + TryFrom<Rhs> + Shl<u32, Output = Lhs> + Shr<u32, Output = Lhs>,
171    Rhs: Copy + Eq + TryFrom<u32> + TryFrom<Lhs> + Shl<u32, Output = Rhs> + Shr<u32, Output = Rhs>,
172{
173    if lhs.bits >= rhs.bits {
174        let Ok(rhs_abs) = Lhs::try_from(rhs.abs) else {
175            unreachable!();
176        };
177        let rhs = Value {
178            neg: rhs.neg,
179            abs: rhs_abs,
180            bits: lhs.bits,
181            frac_bits: rhs.frac_bits,
182        };
183        float_eq_even(lhs, rhs)
184    } else {
185        let Ok(lhs_abs) = Rhs::try_from(lhs.abs) else {
186            unreachable!();
187        };
188        let lhs = Value {
189            neg: lhs.neg,
190            abs: lhs_abs,
191            bits: rhs.bits,
192            frac_bits: lhs.frac_bits,
193        };
194        float_eq_even(lhs, rhs)
195    }
196}
197
198#[inline]
199fn float_cmp_even<U>(lhs: Value<U>, rhs: Value<U>) -> Ordering
200where
201    U: Copy + Ord + TryFrom<u32> + Shl<u32, Output = U> + Shr<u32, Output = U>,
202{
203    if lhs.frac_bits < rhs.frac_bits {
204        return float_cmp_even(rhs, lhs).reverse();
205    }
206
207    if !lhs.neg && rhs.neg {
208        return Ordering::Greater;
209    }
210    if lhs.neg && !rhs.neg {
211        return Ordering::Less;
212    }
213
214    match float_rhs_shl(rhs.abs, rhs.bits, lhs.frac_bits, rhs.frac_bits) {
215        None => {
216            // rhs is so large it doesn't fit
217            if lhs.neg {
218                // both lhs and rhs are negative, and rhs is even more negative
219                Ordering::Greater
220            } else {
221                Ordering::Less
222            }
223        }
224        Some(shifted_rhs_abs) => {
225            if lhs.neg {
226                // both lhs are negative, so reverse order
227                shifted_rhs_abs.cmp(&lhs.abs)
228            } else {
229                lhs.abs.cmp(&shifted_rhs_abs)
230            }
231        }
232    }
233}
234
235#[inline]
236fn float_cmp<Lhs, Rhs>(lhs: Value<Lhs>, rhs: Value<Rhs>) -> Ordering
237where
238    Lhs: Copy + Ord + TryFrom<u32> + TryFrom<Rhs> + Shl<u32, Output = Lhs> + Shr<u32, Output = Lhs>,
239    Rhs: Copy + Ord + TryFrom<u32> + TryFrom<Lhs> + Shl<u32, Output = Rhs> + Shr<u32, Output = Rhs>,
240{
241    if lhs.bits >= rhs.bits {
242        let Ok(rhs_abs) = Lhs::try_from(rhs.abs) else {
243            unreachable!();
244        };
245        let rhs = Value {
246            neg: rhs.neg,
247            abs: rhs_abs,
248            bits: lhs.bits,
249            frac_bits: rhs.frac_bits,
250        };
251        float_cmp_even(lhs, rhs)
252    } else {
253        let Ok(lhs_abs) = Rhs::try_from(lhs.abs) else {
254            unreachable!();
255        };
256        let lhs = Value {
257            neg: lhs.neg,
258            abs: lhs_abs,
259            bits: rhs.bits,
260            frac_bits: lhs.frac_bits,
261        };
262        float_cmp_even(lhs, rhs)
263    }
264}
265
266macro_rules! fixed_cmp_float {
267    ($Fix:ident($Inner:ident), $Float:ident, $FloatBits:ident) => {
268        impl<Frac: Unsigned> PartialEq<$Float> for $Fix<Frac> {
269            #[inline]
270            fn eq(&self, rhs: &$Float) -> bool {
271                use float_helper::$Float::Kind;
272                let (lhs_neg, lhs_abs) = int_helper::$Inner::neg_abs(self.to_bits());
273                let lhs = Value {
274                    neg: lhs_neg,
275                    abs: lhs_abs,
276                    bits: $Inner::BITS,
277                    frac_bits: Frac::to_i32(),
278                };
279                let Kind::Finite {
280                    neg: rhs_neg,
281                    abs: rhs_abs,
282                    frac_bits: rhs_frac,
283                } = float_helper::$Float::kind(*rhs)
284                else {
285                    return false;
286                };
287                let rhs = Value {
288                    neg: rhs_neg,
289                    abs: rhs_abs,
290                    bits: $FloatBits::BITS,
291                    frac_bits: rhs_frac,
292                };
293
294                float_eq(lhs, rhs)
295            }
296        }
297
298        impl<Frac: Unsigned> PartialEq<$Fix<Frac>> for $Float {
299            #[inline]
300            fn eq(&self, rhs: &$Fix<Frac>) -> bool {
301                rhs.eq(self)
302            }
303        }
304
305        impl<Frac: Unsigned> PartialOrd<$Float> for $Fix<Frac> {
306            #[inline]
307            fn partial_cmp(&self, rhs: &$Float) -> Option<Ordering> {
308                use float_helper::$Float::Kind;
309                let (lhs_neg, lhs_abs) = int_helper::$Inner::neg_abs(self.to_bits());
310                let lhs = Value {
311                    neg: lhs_neg,
312                    abs: lhs_abs,
313                    bits: $Inner::BITS,
314                    frac_bits: Frac::to_i32(),
315                };
316                let (rhs_neg, rhs_abs, rhs_frac) = match float_helper::$Float::kind(*rhs) {
317                    Kind::Finite {
318                        neg,
319                        abs,
320                        frac_bits,
321                    } => (neg, abs, frac_bits),
322                    Kind::Infinite { neg } => {
323                        return if neg {
324                            Some(Ordering::Greater)
325                        } else {
326                            Some(Ordering::Less)
327                        };
328                    }
329                    Kind::NaN => return None,
330                };
331                let rhs = Value {
332                    neg: rhs_neg,
333                    abs: rhs_abs,
334                    bits: $FloatBits::BITS,
335                    frac_bits: rhs_frac,
336                };
337
338                Some(float_cmp(lhs, rhs))
339            }
340        }
341
342        impl<Frac: Unsigned> PartialOrd<$Fix<Frac>> for $Float {
343            #[inline]
344            fn partial_cmp(&self, rhs: &$Fix<Frac>) -> Option<Ordering> {
345                rhs.partial_cmp(self).map(Ordering::reverse)
346            }
347        }
348    };
349}
350
351macro_rules! fixed_cmp_all {
352    ($Fix:ident($LeEqU:ident, $Inner:ident)) => {
353        fixed_cmp_int! { $Fix, i8 }
354        fixed_cmp_int! { $Fix, i16 }
355        fixed_cmp_int! { $Fix, i32 }
356        fixed_cmp_int! { $Fix, i64 }
357        fixed_cmp_int! { $Fix, i128 }
358        fixed_cmp_int! { $Fix, isize }
359        fixed_cmp_int! { $Fix, u8 }
360        fixed_cmp_int! { $Fix, u16 }
361        fixed_cmp_int! { $Fix, u32 }
362        fixed_cmp_int! { $Fix, u64 }
363        fixed_cmp_int! { $Fix, u128 }
364        fixed_cmp_int! { $Fix, usize }
365        #[cfg(feature = "nightly-float")]
366        fixed_cmp_float! { $Fix($Inner), f16, u16 }
367        fixed_cmp_float! { $Fix($Inner), half_f16, u16 }
368        fixed_cmp_float! { $Fix($Inner), half_bf16, u16 }
369        fixed_cmp_float! { $Fix($Inner), f32, u32 }
370        fixed_cmp_float! { $Fix($Inner), f64, u64 }
371        #[cfg(feature = "nightly-float")]
372        fixed_cmp_float! { $Fix($Inner), f128, u128 }
373        fixed_cmp_float! { $Fix($Inner), F128, u128 }
374        fixed_cmp_float! { $Fix($Inner), F128Bits, u128 }
375    };
376}
377
378fixed_cmp_all! { FixedI8(LeEqU8, i8) }
379fixed_cmp_all! { FixedI16(LeEqU16, i16) }
380fixed_cmp_all! { FixedI32(LeEqU32, i32) }
381fixed_cmp_all! { FixedI64(LeEqU64, i64) }
382fixed_cmp_all! { FixedI128(LeEqU128, i128) }
383fixed_cmp_all! { FixedU8(LeEqU8, u8) }
384fixed_cmp_all! { FixedU16(LeEqU16, u16) }
385fixed_cmp_all! { FixedU32(LeEqU32, u32) }
386fixed_cmp_all! { FixedU64(LeEqU64, u64) }
387fixed_cmp_all! { FixedU128(LeEqU128, u128) }
388
389#[cfg(test)]
390mod tests {
391    use crate::*;
392    use core::cmp::Ordering;
393
394    #[test]
395    fn cmp_signed() {
396        use core::cmp::Ordering::*;
397        let neg1_16 = FixedI32::<types::extra::U16>::NEG_ONE;
398        let neg1_20 = FixedI32::<types::extra::U20>::NEG_ONE;
399        let mut a = neg1_16;
400        let mut b = neg1_20;
401        // a = ffff.0000 = -1, b = fff.00000 = -1
402        assert!(a.eq(&b) && b.eq(&a));
403        assert_eq!(a.partial_cmp(&b), Some(Equal));
404        assert_eq!(b.partial_cmp(&a), Some(Equal));
405        assert_eq!(a, -1i8);
406        assert_eq!(b, -1i128);
407        a >>= 16;
408        b >>= 16;
409        // a = ffff.ffff = -2^-16, b = fff.ffff0 = -2^-16
410        assert!(a.eq(&b) && b.eq(&a));
411        assert_eq!(a.partial_cmp(&b), Some(Equal));
412        assert_eq!(b.partial_cmp(&a), Some(Equal));
413        assert!(a < 0.0);
414        assert_eq!(a.partial_cmp(&f32::INFINITY), Some(Less));
415        assert!(a < f32::INFINITY);
416        assert!(a != f32::INFINITY);
417        assert_eq!(a.partial_cmp(&f32::NEG_INFINITY), Some(Greater));
418        assert!(a > f32::NEG_INFINITY);
419        assert_eq!(a, -(-16f32).exp2());
420        assert!(a <= -(-16f32).exp2());
421        assert!(a >= -(-16f32).exp2());
422        assert!(a < (-16f32).exp2());
423        assert_ne!(a, -0.75 * (-16f32).exp2());
424        assert!(a < -0.75 * (-16f32).exp2());
425        assert!(a <= -0.75 * (-16f32).exp2());
426        assert!(a > -1.25 * (-16f32).exp2());
427        assert!(a >= -1.25 * (-16f32).exp2());
428        a >>= 1;
429        b >>= 1;
430        // a = ffff.ffff = -2^-16, b = fff.ffff8 = -2^-17
431        assert!(a.ne(&b) && b.ne(&a));
432        assert_eq!(a.partial_cmp(&b), Some(Less));
433        assert_eq!(b.partial_cmp(&a), Some(Greater));
434        a = neg1_16 << 11;
435        b = neg1_20 << 11;
436        // a = f800.0000 = -2^11, b = 800.00000 = -2^11
437        assert!(a.eq(&b) && b.eq(&a));
438        assert_eq!(a.partial_cmp(&b), Some(Equal));
439        assert_eq!(b.partial_cmp(&a), Some(Equal));
440        assert_eq!(a, -1i16 << 11);
441        assert_eq!(b, -1i64 << 11);
442        a <<= 1;
443        b <<= 1;
444        // a = f000.0000 = -2^-12, b = 000.00000 = 0
445        assert!(a.ne(&b) && b.ne(&a));
446        assert_eq!(a.partial_cmp(&b), Some(Less));
447        assert_eq!(b.partial_cmp(&a), Some(Greater));
448        assert!(a < 1u8);
449        assert_eq!(b, 0);
450    }
451
452    #[test]
453    fn cmp_unsigned() {
454        use core::cmp::Ordering::*;
455        let one_16 = FixedU32::<types::extra::U16>::ONE;
456        let one_20 = FixedU32::<types::extra::U20>::ONE;
457        let mut a = one_16;
458        let mut b = one_20;
459        // a = 0001.0000 = 1, b = 001.00000 = 1
460        assert!(a.eq(&b) && b.eq(&a));
461        assert_eq!(a.partial_cmp(&b), Some(Equal));
462        assert_eq!(b.partial_cmp(&a), Some(Equal));
463        assert_eq!(a, 1u8);
464        assert_eq!(b, 1i128);
465        a >>= 16;
466        b >>= 16;
467        // a = 0000.0001 = 2^-16, b = 000.00010 = 2^-16
468        assert!(a.eq(&b) && b.eq(&a));
469        assert_eq!(a.partial_cmp(&b), Some(Equal));
470        assert_eq!(b.partial_cmp(&a), Some(Equal));
471        assert!(a > 0.0);
472        assert_eq!(a.partial_cmp(&f32::INFINITY), Some(Less));
473        assert!(a < f32::INFINITY);
474        assert!(a != f32::INFINITY);
475        assert_eq!(a.partial_cmp(&f32::NEG_INFINITY), Some(Greater));
476        assert!(a > f32::NEG_INFINITY);
477        assert_eq!(a, (-16f64).exp2());
478        assert!(a <= (-16f64).exp2());
479        assert!(a >= (-16f64).exp2());
480        assert!(a > -(-16f64).exp2());
481        assert_ne!(a, 0.75 * (-16f64).exp2());
482        assert!(a > 0.75 * (-16f64).exp2());
483        assert!(a >= 0.75 * (-16f64).exp2());
484        assert!(a < 1.25 * (-16f64).exp2());
485        assert!(a <= 1.25 * (-16f64).exp2());
486        a >>= 1;
487        b >>= 1;
488        // a = 0000.0000 = 0, b = 000.00008 = 2^-17
489        assert!(a.ne(&b) && b.ne(&a));
490        assert_eq!(a.partial_cmp(&b), Some(Less));
491        assert_eq!(b.partial_cmp(&a), Some(Greater));
492        a = one_16 << 11;
493        b = one_20 << 11;
494        // a = 0800.0000 = 2^11, b = 800.00000 = 2^11
495        assert!(a.eq(&b) && b.eq(&a));
496        assert_eq!(a.partial_cmp(&b), Some(Equal));
497        assert_eq!(b.partial_cmp(&a), Some(Equal));
498        assert_eq!(a, 1i16 << 11);
499        assert_eq!(b, 1u64 << 11);
500        a <<= 1;
501        b <<= 1;
502        // a = 1000.0000 = 2^12, b = 000.00000 = 0
503        assert!(a.ne(&b) && b.ne(&a));
504        assert_eq!(a.partial_cmp(&b), Some(Greater));
505        assert_eq!(b.partial_cmp(&a), Some(Less));
506        assert!(a > -1i8);
507        assert_eq!(a, 1i32 << 12);
508        assert_eq!(b, 0);
509    }
510
511    #[test]
512    fn cmp_i0() {
513        use crate::types::*;
514        assert_eq!(I0F32::checked_from_num(0.5), None);
515        for &float in &[
516            -0.5,
517            -0.5 + f32::EPSILON,
518            -0.25,
519            -f32::EPSILON,
520            0.0,
521            f32::EPSILON,
522            0.25,
523            0.5 - f32::EPSILON,
524        ] {
525            let fixed = I0F32::from_num(float);
526            let half = U0F32::from_num(0.5);
527            assert_eq!(fixed < half, float < 0.5, "{fixed} < {half}");
528            assert_eq!(fixed <= half, float <= 0.5, "{fixed} <= {half}");
529            assert_eq!(fixed == half, float == 0.5, "{fixed} == {half}");
530            assert_eq!(fixed >= half, float >= 0.5, "{fixed} >= {half}");
531            assert_eq!(fixed > half, float > 0.5, "{fixed} > {half}");
532            assert_eq!(
533                fixed.partial_cmp(&half),
534                float.partial_cmp(&0.5),
535                "{fixed}.partial_cmp(&{half})"
536            );
537            assert_eq!(half < fixed, fixed > half);
538            assert_eq!(half <= fixed, fixed >= half);
539            assert_eq!(half == fixed, fixed == half);
540            assert_eq!(half >= fixed, fixed <= half);
541            assert_eq!(half > fixed, fixed < half);
542            assert_eq!(
543                half.partial_cmp(&fixed),
544                fixed.partial_cmp(&half).map(Ordering::reverse)
545            );
546
547            let half = I1F31::from_num(0.5);
548            assert_eq!(fixed < half, float < 0.5, "{fixed} < {half}");
549            assert_eq!(fixed <= half, float <= 0.5, "{fixed} <= {half}");
550            assert_eq!(fixed == half, float == 0.5, "{fixed} == {half}");
551            assert_eq!(fixed >= half, float >= 0.5, "{fixed} >= {half}");
552            assert_eq!(fixed > half, float > 0.5, "{fixed} > {half}");
553            assert_eq!(
554                fixed.partial_cmp(&half),
555                float.partial_cmp(&0.5),
556                "{fixed}.partial_cmp(&{half})"
557            );
558            assert_eq!(half < fixed, fixed > half);
559            assert_eq!(half <= fixed, fixed >= half);
560            assert_eq!(half == fixed, fixed == half);
561            assert_eq!(half >= fixed, fixed <= half);
562            assert_eq!(half > fixed, fixed < half);
563            assert_eq!(
564                half.partial_cmp(&fixed),
565                fixed.partial_cmp(&half).map(Ordering::reverse)
566            );
567
568            let half = 0.5f32;
569            assert_eq!(fixed < half, float < 0.5, "{fixed} < {half}");
570            assert_eq!(fixed <= half, float <= 0.5, "{fixed} <= {half}");
571            assert_eq!(fixed == half, float == 0.5, "{fixed} == {half}");
572            assert_eq!(fixed >= half, float >= 0.5, "{fixed} >= {half}");
573            assert_eq!(fixed > half, float > 0.5, "{fixed} > {half}");
574            assert_eq!(
575                fixed.partial_cmp(&half),
576                float.partial_cmp(&0.5),
577                "{fixed}.partial_cmp(&{half})"
578            );
579            assert_eq!(half < fixed, fixed > half);
580            assert_eq!(half <= fixed, fixed >= half);
581            assert_eq!(half == fixed, fixed == half);
582            assert_eq!(half >= fixed, fixed <= half);
583            assert_eq!(half > fixed, fixed < half);
584            assert_eq!(
585                half.partial_cmp(&fixed),
586                fixed.partial_cmp(&half).map(Ordering::reverse)
587            );
588
589            let m1 = I32F0::from_num(-1.0);
590            assert_eq!(fixed < m1, float < -1.0, "{fixed} < {m1}");
591            assert_eq!(fixed <= m1, float <= -1.0, "{fixed} <= {m1}");
592            assert_eq!(fixed == m1, float == -1.0, "{fixed} == {m1}");
593            assert_eq!(fixed >= m1, float >= -1.0, "{fixed} >= {m1}");
594            assert_eq!(fixed > m1, float > -1.0, "{fixed} > {m1}");
595            assert_eq!(
596                fixed.partial_cmp(&m1),
597                float.partial_cmp(&-1.0),
598                "{fixed}.partial_cmp(&{m1})"
599            );
600            assert_eq!(m1 < fixed, fixed > m1);
601            assert_eq!(m1 <= fixed, fixed >= m1);
602            assert_eq!(m1 == fixed, fixed == m1);
603            assert_eq!(m1 >= fixed, fixed <= m1);
604            assert_eq!(m1 > fixed, fixed < m1);
605            assert_eq!(
606                m1.partial_cmp(&fixed),
607                fixed.partial_cmp(&m1).map(Ordering::reverse)
608            );
609
610            let m1 = I1F31::from_num(-1.0);
611            assert_eq!(fixed < m1, float < -1.0, "{fixed} < {m1}");
612            assert_eq!(fixed <= m1, float <= -1.0, "{fixed} <= {m1}");
613            assert_eq!(fixed == m1, float == -1.0, "{fixed} == {m1}");
614            assert_eq!(fixed >= m1, float >= -1.0, "{fixed} >= {m1}");
615            assert_eq!(fixed > m1, float > -1.0, "{fixed} > {m1}");
616            assert_eq!(
617                fixed.partial_cmp(&m1),
618                float.partial_cmp(&-1.0),
619                "{fixed}.partial_cmp(&{m1})"
620            );
621            assert_eq!(m1 < fixed, fixed > m1);
622            assert_eq!(m1 <= fixed, fixed >= m1);
623            assert_eq!(m1 == fixed, fixed == m1);
624            assert_eq!(m1 >= fixed, fixed <= m1);
625            assert_eq!(m1 > fixed, fixed < m1);
626            assert_eq!(
627                m1.partial_cmp(&fixed),
628                fixed.partial_cmp(&m1).map(Ordering::reverse)
629            );
630
631            let m1 = -1.0f32;
632            assert_eq!(fixed < m1, float < -1.0, "{fixed} < {m1}");
633            assert_eq!(fixed <= m1, float <= -1.0, "{fixed} <= {m1}");
634            assert_eq!(fixed == m1, float == -1.0, "{fixed} == {m1}");
635            assert_eq!(fixed >= m1, float >= -1.0, "{fixed} >= {m1}");
636            assert_eq!(fixed > m1, float > -1.0, "{fixed} > {m1}");
637            assert_eq!(
638                fixed.partial_cmp(&m1),
639                float.partial_cmp(&-1.0),
640                "{fixed}.partial_cmp(&{m1})"
641            );
642            assert_eq!(m1 < fixed, fixed > m1);
643            assert_eq!(m1 <= fixed, fixed >= m1);
644            assert_eq!(m1 == fixed, fixed == m1);
645            assert_eq!(m1 >= fixed, fixed <= m1);
646            assert_eq!(m1 > fixed, fixed < m1);
647            assert_eq!(
648                m1.partial_cmp(&fixed),
649                fixed.partial_cmp(&m1).map(Ordering::reverse)
650            );
651
652            let mhalf = I1F31::from_num(-0.5);
653            assert_eq!(fixed < mhalf, float < -0.5, "{fixed} < {mhalf}");
654            assert_eq!(fixed <= mhalf, float <= -0.5, "{fixed} <= {mhalf}");
655            assert_eq!(fixed == mhalf, float == -0.5, "{fixed} == {mhalf}");
656            assert_eq!(fixed >= mhalf, float >= -0.5, "{fixed} >= {mhalf}");
657            assert_eq!(fixed > mhalf, float > -0.5, "{fixed} > {mhalf}");
658            assert_eq!(
659                fixed.partial_cmp(&mhalf),
660                float.partial_cmp(&-0.5),
661                "{fixed}.partial_cmp(&{mhalf})"
662            );
663            assert_eq!(mhalf < fixed, fixed > mhalf);
664            assert_eq!(mhalf <= fixed, fixed >= mhalf);
665            assert_eq!(mhalf == fixed, fixed == mhalf);
666            assert_eq!(mhalf >= fixed, fixed <= mhalf);
667            assert_eq!(mhalf > fixed, fixed < mhalf);
668            assert_eq!(
669                mhalf.partial_cmp(&fixed),
670                fixed.partial_cmp(&mhalf).map(Ordering::reverse)
671            );
672
673            let mhalf = -0.5f32;
674            assert_eq!(fixed < mhalf, float < -0.5, "{fixed} < {mhalf}");
675            assert_eq!(fixed <= mhalf, float <= -0.5, "{fixed} <= {mhalf}");
676            assert_eq!(fixed == mhalf, float == -0.5, "{fixed} == {mhalf}");
677            assert_eq!(fixed >= mhalf, float >= -0.5, "{fixed} >= {mhalf}");
678            assert_eq!(fixed > mhalf, float > -0.5, "{fixed} > {mhalf}");
679            assert_eq!(
680                fixed.partial_cmp(&mhalf),
681                float.partial_cmp(&-0.5),
682                "{fixed}.partial_cmp(&{mhalf})"
683            );
684            assert_eq!(mhalf < fixed, fixed > mhalf);
685            assert_eq!(mhalf <= fixed, fixed >= mhalf);
686            assert_eq!(mhalf == fixed, fixed == mhalf);
687            assert_eq!(mhalf >= fixed, fixed <= mhalf);
688            assert_eq!(mhalf > fixed, fixed < mhalf);
689            assert_eq!(
690                mhalf.partial_cmp(&fixed),
691                fixed.partial_cmp(&mhalf).map(Ordering::reverse)
692            );
693        }
694    }
695}