1use crate::NumOrd;
2use core::cmp::Ordering;
3use core::convert::TryFrom;
4#[cfg(feature = "num-rational")]
5use num_modular::udouble;
6
7#[allow(unused_macros)]
9macro_rules! impl_ord_by_swap {
10 ($($t1:ty | $t2:ty;)*) => ($(
11 impl NumOrd<$t2> for $t1 {
12 #[inline]
13 fn num_partial_cmp(&self, other: &$t2) -> Option<Ordering> {
14 other.num_partial_cmp(self).map(Ordering::reverse)
15 }
16 }
17 )*);
18}
19
20macro_rules! impl_ord_equal_types {
22 ($($t:ty)*) => ($(
23 impl NumOrd<$t> for $t {
24 #[inline]
25 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
26 self.partial_cmp(&other)
27 }
28 }
29 )*);
30}
31
32impl_ord_equal_types! {
33 u8 u16 u32 u64 u128 usize
34 i8 i16 i32 i64 i128 isize
35 f32 f64
36}
37
38macro_rules! impl_ord_by_casting {
40 ($($small:ty => $big:ty;)*) => ($(
41 impl NumOrd<$small> for $big {
42 #[inline]
43 fn num_partial_cmp(&self, other: &$small) -> Option<Ordering> {
44 self.partial_cmp(&<$big>::from(*other))
45 }
46 }
47 impl NumOrd<$big> for $small {
48 #[inline]
49 fn num_partial_cmp(&self, other: &$big) -> Option<Ordering> {
50 <$big>::from(*self).partial_cmp(other)
51 }
52 }
53 )*);
54}
55
56impl_ord_by_casting! {
57 u8 => u128; u8 => u64; u8 => u32; u8 => u16;
59 u16 => u128; u16 => u64; u16 => u32;
60 u32 => u128; u32 => u64;
61 u64 => u128;
62
63 i8 => i128; i8 => i64; i8 => i32; i8 => i16;
65 i16 => i128; i16 => i64; i16 => i32;
66 i32 => i128; i32 => i64;
67 i64 => i128;
68
69 u8 => i128; u8 => i64; u8 => i32; u8 => i16;
71 u16 => i128; u16 => i64; u16 => i32;
72 u32 => i128; u32 => i64;
73 u64 => i128;
74
75 f32 => f64;
77
78 u8 => f32; u16 => f32;
81 u8 => f64; u16 => f64; u32 => f64;
82
83 i8 => f32; i16 => f32;
87 i8 => f64; i16 => f64; i32 => f64;
88}
89
90macro_rules! impl_ord_between_diff_sign {
92 ($($signed:ty => $unsigned:ty;)*) => ($(
93 impl NumOrd<$signed> for $unsigned {
94 #[inline]
95 fn num_partial_cmp(&self, other: &$signed) -> Option<Ordering> {
96 if other < &0 {
97 Some(Ordering::Greater)
98 } else {
99 self.partial_cmp(&<$unsigned>::try_from(*other).unwrap())
100 }
101 }
102 }
103 impl NumOrd<$unsigned> for $signed {
104 #[inline]
105 fn num_partial_cmp(&self, other: &$unsigned) -> Option<Ordering> {
106 if self < &0 {
107 Some(Ordering::Less)
108 } else {
109 <$unsigned>::try_from(*self).unwrap().partial_cmp(other)
110 }
111 }
112 }
113 )*);
114}
115
116impl_ord_between_diff_sign! {
117 i8 => u128; i8 => u64; i8 => u32 ; i8 => u16; i8 => u8;
118 i16 => u128; i16 => u64; i16 => u32 ; i16 => u16;
119 i32 => u128; i32 => u64; i32 => u32 ;
120 i64 => u128; i64 => u64;
121 i128 => u128; isize => usize;
122}
123
124trait FloatExp {
128 fn e(self) -> i16;
130}
131impl FloatExp for f32 {
132 #[inline]
133 fn e(self) -> i16 {
134 (self.to_bits() >> 23 & 0xff) as i16 - (0x7f + 23)
135 }
136}
137impl FloatExp for f64 {
138 #[inline]
139 fn e(self) -> i16 {
140 (self.to_bits() >> 52 & 0x7ff) as i16 - (0x3ff + 52)
141 }
142}
143
144macro_rules! impl_ord_between_int_float {
145 ($($float:ty | $int:ty;)*) => ($(
146 impl NumOrd<$float> for $int {
147 #[inline]
148 fn num_partial_cmp(&self, other: &$float) -> Option<Ordering> {
149 if other.is_nan() {
150 None
151 } else if other < &(<$int>::MIN as $float) { Some(Ordering::Greater)
153 } else if other >= &(<$int>::MAX as $float) { Some(Ordering::Less)
155 } else if other.e() >= 0 { self.partial_cmp(&(*other as $int))
157 } else {
158 let trunc = *other as $int;
159 (*self, trunc as $float).partial_cmp(&(trunc, *other))
160 }
161 }
162 }
163 impl NumOrd<$int> for $float {
164 #[inline]
165 fn num_partial_cmp(&self, other: &$int) -> Option<Ordering> {
166 if self.is_nan() {
167 None
168 } else if self < &(<$int>::MIN as $float) { Some(Ordering::Less)
170 } else if self >= &(<$int>::MAX as $float) { Some(Ordering::Greater)
172 } else if self.e() >= 0 { (*self as $int).partial_cmp(other)
174 } else {
175 let trunc = *other as $int;
176 (trunc, *self).partial_cmp(&(*other, trunc as $float))
177 }
178 }
179 }
180 )*);
181}
182
183impl_ord_between_int_float! {
184 f32|u128; f32|i128; f32|u64; f32|i64; f32|u32; f32|i32;
185 f64|u128; f64|i128; f64|u64; f64|i64;
186}
187
188macro_rules! impl_ord_with_size_types {
190 ($($t:ty)*) => ($(
191 impl NumOrd<$t> for usize {
192 #[inline]
193 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
194 #[cfg(target_pointer_width = "32")]
195 { (*self as u32).num_partial_cmp(other) }
196 #[cfg(target_pointer_width = "64")]
197 { (*self as u64).num_partial_cmp(other) }
198 }
199 }
200 impl NumOrd<usize> for $t {
201 #[inline]
202 fn num_partial_cmp(&self, other: &usize) -> Option<Ordering> {
203 #[cfg(target_pointer_width = "32")]
204 { self.num_partial_cmp(&(*other as u32)) }
205 #[cfg(target_pointer_width = "64")]
206 { self.num_partial_cmp(&(*other as u64)) }
207 }
208 }
209 impl NumOrd<$t> for isize {
210 #[inline]
211 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
212 #[cfg(target_pointer_width = "32")]
213 { (*self as i32).num_partial_cmp(other) }
214 #[cfg(target_pointer_width = "64")]
215 { (*self as i64).num_partial_cmp(other) }
216 }
217 }
218 impl NumOrd<isize> for $t {
219 #[inline]
220 fn num_partial_cmp(&self, other: &isize) -> Option<Ordering> {
221 #[cfg(target_pointer_width = "32")]
222 { self.num_partial_cmp(&(*other as i32)) }
223 #[cfg(target_pointer_width = "64")]
224 { self.num_partial_cmp(&(*other as i64)) }
225 }
226 }
227 )*);
228}
229
230impl_ord_with_size_types!(u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64);
231
232#[cfg(feature = "num-bigint")]
234mod _num_bigint {
235 use super::*;
236 use num_bigint::{BigInt, BigUint};
237 use num_traits::{FromPrimitive, Signed};
238
239 impl_ord_equal_types!(BigInt BigUint);
240 impl_ord_by_casting! {
241 u8 => BigUint; u16 => BigUint; u32 => BigUint; u64 => BigUint; u128 => BigUint;
242 i8 => BigInt; i16 => BigInt; i32 => BigInt; i64 => BigInt; i128 => BigInt;
243 u8 => BigInt; u16 => BigInt; u32 => BigInt; u64 => BigInt; u128 => BigInt;
244 }
245 impl_ord_between_diff_sign! {
246 i8 => BigUint; i16 => BigUint; i32 => BigUint; i64 => BigUint; i128 => BigUint;
247 }
248 impl_ord_with_size_types! (BigInt BigUint);
249
250 impl NumOrd<f32> for BigUint {
252 #[inline]
253 fn num_partial_cmp(&self, other: &f32) -> Option<Ordering> {
254 if other.is_nan() {
255 None
256 } else if other < &0. {
257 Some(Ordering::Greater)
258 } else if other.is_infinite() && other.is_sign_positive() {
259 Some(Ordering::Less)
260 } else {
261 let trunc = other.trunc();
262 (self, &trunc).partial_cmp(&(&BigUint::from_f32(trunc).unwrap(), other))
263 }
264 }
265 }
266 impl NumOrd<f64> for BigUint {
267 #[inline]
268 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
269 if other.is_nan() {
270 None
271 } else if other < &0. {
272 Some(Ordering::Greater)
273 } else if other.is_infinite() && other.is_sign_positive() {
274 Some(Ordering::Less)
275 } else {
276 let trunc = other.trunc();
277 (self, &trunc).partial_cmp(&(&BigUint::from_f64(trunc).unwrap(), other))
278 }
279 }
280 }
281 impl NumOrd<f32> for BigInt {
282 #[inline]
283 fn num_partial_cmp(&self, other: &f32) -> Option<Ordering> {
284 if other.is_nan() {
285 None
286 } else if other.is_infinite() {
287 if other.is_sign_positive() {
288 Some(Ordering::Less)
289 } else {
290 Some(Ordering::Greater)
291 }
292 } else {
293 let trunc = other.trunc();
294 (self, &trunc).partial_cmp(&(&BigInt::from_f32(trunc).unwrap(), other))
295 }
296 }
297 }
298 impl NumOrd<f64> for BigInt {
299 #[inline]
300 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
301 if other.is_nan() {
302 None
303 } else if other.is_infinite() {
304 if other.is_sign_positive() {
305 Some(Ordering::Less)
306 } else {
307 Some(Ordering::Greater)
308 }
309 } else {
310 let trunc = other.trunc();
311 (self, &trunc).partial_cmp(&(&BigInt::from_f64(trunc).unwrap(), other))
312 }
313 }
314 }
315 impl NumOrd<BigInt> for BigUint {
316 #[inline]
317 fn num_partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
318 if other.is_negative() {
319 Some(Ordering::Greater)
320 } else {
321 self.partial_cmp(other.magnitude())
322 }
323 }
324 }
325 impl_ord_by_swap! { f32|BigInt; f32|BigUint; f64|BigInt; f64|BigUint; BigInt|BigUint; }
326}
327
328#[cfg(feature = "num-rational")]
333mod _num_rational {
334 use super::*;
335 use num_rational::Ratio;
336 use num_traits::{float::FloatCore, CheckedMul, Signed, Zero};
337
338 impl_ord_equal_types!(
339 Ratio<i8> Ratio<i16> Ratio<i32> Ratio<i64> Ratio<i128> Ratio<isize>
340 Ratio<u8> Ratio<u16> Ratio<u32> Ratio<u64> Ratio<u128> Ratio<usize>
341 );
342
343 macro_rules! impl_ratio_ord_with_int {
344 ($($t:ty)*) => ($(
345 impl NumOrd<Ratio<$t>> for $t {
346 #[inline]
347 fn num_partial_cmp(&self, other: &Ratio<$t>) -> Option<Ordering> {
348 (self * other.denom()).partial_cmp(other.numer())
349 }
350 }
351 impl NumOrd<$t> for Ratio<$t> {
352 #[inline]
353 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
354 self.numer().partial_cmp(&(other * self.denom()))
355 }
356 }
357 )*);
358 }
359 impl_ratio_ord_with_int!(i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize);
360
361 macro_rules! impl_ratio_ord_by_casting {
362 ($($small:ty => $big:ty;)*) => ($(
363 impl NumOrd<Ratio<$small>> for Ratio<$big> {
365 #[inline]
366 fn num_partial_cmp(&self, other: &Ratio<$small>) -> Option<Ordering> {
367 let r = Ratio::new(<$big>::from(*other.numer()), <$big>::from(*other.denom()));
368 self.partial_cmp(&r)
369 }
370 }
371 impl NumOrd<Ratio<$big>> for Ratio<$small> {
372 #[inline]
373 fn num_partial_cmp(&self, other: &Ratio<$big>) -> Option<Ordering> {
374 let r = Ratio::new(<$big>::from(*self.numer()), <$big>::from(*self.denom()));
375 r.partial_cmp(other)
376 }
377 }
378
379 impl NumOrd<$small> for Ratio<$big> {
381 #[inline]
382 fn num_partial_cmp(&self, other: &$small) -> Option<Ordering> {
383 if let Some(prod) = self.denom().checked_mul(&<$big>::from(*other)) {
384 self.numer().partial_cmp(&prod)
385 } else {
386 Some(Ordering::Less)
387 }
388 }
389 }
390 impl NumOrd<Ratio<$big>> for $small {
391 #[inline]
392 fn num_partial_cmp(&self, other: &Ratio<$big>) -> Option<Ordering> {
393 if let Some(prod) = other.denom().checked_mul(&<$big>::from(*self)) {
394 prod.partial_cmp(other.numer())
395 } else {
396 Some(Ordering::Greater)
397 }
398 }
399 }
400 impl NumOrd<$big> for Ratio<$small> {
401 #[inline]
402 fn num_partial_cmp(&self, other: &$big) -> Option<Ordering> {
403 if let Some(prod) = other.checked_mul(&<$big>::from(*self.denom())) {
404 <$big>::from(*self.numer()).partial_cmp(&prod)
405 } else {
406 Some(Ordering::Less)
407 }
408 }
409 }
410 impl NumOrd<Ratio<$small>> for $big {
411 #[inline]
412 fn num_partial_cmp(&self, other: &Ratio<$small>) -> Option<Ordering> {
413 if let Some(prod) = self.checked_mul(&<$big>::from(*other.denom())) {
414 prod.partial_cmp(&<$big>::from(*other.numer()))
415 } else {
416 Some(Ordering::Greater)
417 }
418 }
419 }
420 )*);
421 }
422 impl_ratio_ord_by_casting! {
423 u8 => u128; u8 => u64; u8 => u32; u8 => u16;
425 u16 => u128; u16 => u64; u16 => u32;
426 u32 => u128; u32 => u64;
427 u64 => u128;
428
429 i8 => i128; i8 => i64; i8 => i32; i8 => i16;
431 i16 => i128; i16 => i64; i16 => i32;
432 i32 => i128; i32 => i64;
433 i64 => i128;
434
435 u8 => i128; u8 => i64; u8 => i32; u8 => i16;
437 u16 => i128; u16 => i64; u16 => i32;
438 u32 => i128; u32 => i64;
439 u64 => i128;
440 }
441
442 macro_rules! impl_ratio_ord_between_diff_sign {
444 ($($int:ty => $uint:ty;)*) => ($(
445 impl NumOrd<Ratio<$uint>> for Ratio<$int> {
447 #[inline]
448 fn num_partial_cmp(&self, other: &Ratio<$uint>) -> Option<Ordering> {
449 if self.is_negative() {
450 Some(Ordering::Less)
451 } else {
452 let r = Ratio::<$uint>::new(<$uint>::try_from(*self.numer()).unwrap(), <$uint>::try_from(*self.denom()).unwrap());
453 r.partial_cmp(other)
454 }
455 }
456 }
457 impl NumOrd<Ratio<$int>> for Ratio<$uint> {
458 #[inline]
459 fn num_partial_cmp(&self, other: &Ratio<$int>) -> Option<Ordering> {
460 if other.is_negative() {
461 Some(Ordering::Greater)
462 } else {
463 let r = Ratio::<$uint>::new(<$uint>::try_from(*other.numer()).unwrap(), <$uint>::try_from(*other.denom()).unwrap());
464 self.partial_cmp(&r)
465 }
466 }
467 }
468
469 impl NumOrd<$uint> for Ratio<$int> {
471 #[inline]
472 fn num_partial_cmp(&self, other: &$uint) -> Option<Ordering> {
473 if self.is_negative() {
474 Some(Ordering::Less)
475 } else {
476 <$uint>::try_from(*self.numer()).unwrap().partial_cmp(&(<$uint>::try_from(*self.denom()).unwrap() * other))
477 }
478 }
479 }
480 impl NumOrd<Ratio<$int>> for $uint {
481 #[inline]
482 fn num_partial_cmp(&self, other: &Ratio<$int>) -> Option<Ordering> {
483 if other.is_negative() {
484 Some(Ordering::Greater)
485 } else {
486 (<$uint>::try_from(*other.denom()).unwrap() * self).partial_cmp(&<$uint>::try_from(*other.numer()).unwrap())
487 }
488 }
489 }
490 impl NumOrd<$int> for Ratio<$uint> {
491 #[inline]
492 fn num_partial_cmp(&self, other: &$int) -> Option<Ordering> {
493 if other.is_negative() {
494 Some(Ordering::Greater)
495 } else {
496 self.numer().partial_cmp(&(<$uint>::try_from(*other).unwrap() * self.denom()))
497 }
498 }
499 }
500 impl NumOrd<Ratio<$uint>> for $int {
501 #[inline]
502 fn num_partial_cmp(&self, other: &Ratio<$uint>) -> Option<Ordering> {
503 if self.is_negative() {
504 Some(Ordering::Less)
505 } else {
506 (<$uint>::try_from(*self).unwrap() * other.denom()).partial_cmp(other.numer())
507 }
508 }
509 }
510 )*);
511 }
512 impl_ratio_ord_between_diff_sign! {
513 i8 => u128; i8 => u64; i8 => u32; i8 => u16; i8 => u8;
514 i16 => u128; i16 => u64; i16 => u32; i16 => u16;
515 i32 => u128; i32 => u64; i32 => u32;
516 i64 => u128; i64 => u64;
517 i128 => u128; isize => usize;
518 }
519
520 macro_rules! float_cmp_shortcuts {
521 ($ratio:tt, $float:tt) => {
522 if $ratio.is_zero() {
524 return 0f64.partial_cmp($float);
525 }
526 if $float.is_zero() {
527 return $ratio.numer().partial_cmp(&0);
528 }
529
530 if $float.is_nan() {
532 return None;
533 } else if $float.is_infinite() {
534 if $float.is_sign_positive() {
535 return Some(Ordering::Less);
536 } else {
537 return Some(Ordering::Greater);
539 }
540 }
541 };
542 }
543
544 impl NumOrd<f64> for Ratio<u64> {
546 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
547 float_cmp_shortcuts!(self, other);
548
549 let (man, exp, sign) = other.integer_decode();
551 if sign < 0 {
552 return Some(Ordering::Greater);
553 }
554
555 let a = *self.numer();
557 let b = *self.denom();
558
559 let result = if exp >= 0 {
560 if let Some(den) = || -> Option<_> {
562 1u64.checked_shl(exp as u32)?
563 .checked_mul(man)?
564 .checked_mul(b)
565 }() {
566 a.partial_cmp(&den).unwrap()
567 } else {
568 Ordering::Less
569 }
570 } else {
571 let den = man as u128 * b as u128;
573 if let Some(num) =
574 || -> Option<_> { 1u128.checked_shl((-exp) as u32)?.checked_mul(a as u128) }()
575 {
576 num.partial_cmp(&den).unwrap()
577 } else {
578 Ordering::Greater
579 }
580 };
581 Some(result)
582 }
583 }
584 impl NumOrd<f64> for Ratio<i64> {
585 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
586 float_cmp_shortcuts!(self, other);
587
588 let (man, exp, sign) = other.integer_decode();
590 let reverse = match (!self.is_negative(), sign >= 0) {
591 (true, false) => return Some(Ordering::Greater),
592 (false, true) => return Some(Ordering::Less),
593 (true, true) => false,
594 (false, false) => true,
595 };
596
597 let a = if self.numer() < &0 {
599 (*self.numer() as u64).wrapping_neg()
600 } else {
601 *self.numer() as u64
602 };
603 let b = if self.denom() < &0 {
604 (*self.denom() as u64).wrapping_neg()
605 } else {
606 *self.denom() as u64
607 };
608
609 let result = if exp >= 0 {
610 if let Some(den) = || -> Option<_> {
612 1u64.checked_shl(exp as u32)?
613 .checked_mul(man)?
614 .checked_mul(b)
615 }() {
616 a.partial_cmp(&den).unwrap()
617 } else {
618 Ordering::Less
619 }
620 } else {
621 let den = man as u128 * b as u128;
623 if let Some(num) =
624 || -> Option<_> { 1u128.checked_shl((-exp) as u32)?.checked_mul(a as u128) }()
625 {
626 num.partial_cmp(&den).unwrap()
627 } else {
628 Ordering::Greater
629 }
630 };
631
632 if reverse {
633 Some(result.reverse())
634 } else {
635 Some(result)
636 }
637 }
638 }
639 impl NumOrd<f64> for Ratio<u128> {
640 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
641 float_cmp_shortcuts!(self, other);
642
643 let (man, exp, sign) = other.integer_decode();
645 if sign < 0 {
646 return Some(Ordering::Greater);
647 }
648
649 let a = *self.numer();
651 let b = *self.denom();
652
653 let result = if exp >= 0 {
654 if let Some(num) = || -> Option<_> {
656 1u128
657 .checked_shl(exp as u32)?
658 .checked_mul(man as u128)?
659 .checked_mul(b)
660 }() {
661 a.partial_cmp(&num).unwrap()
662 } else {
663 Ordering::Less
664 }
665 } else {
666 let den = udouble::widening_mul(man as u128, b);
668 if let Some(num) = || -> Option<_> {
669 let (v, o) = udouble { lo: 1, hi: 0 }
670 .checked_shl((-exp) as u32)?
671 .overflowing_mul1(a);
672 if !o {
673 Some(v)
674 } else {
675 None
676 }
677 }() {
678 num.partial_cmp(&den).unwrap()
679 } else {
680 Ordering::Greater
681 }
682 };
683 Some(result)
684 }
685 }
686 impl NumOrd<f64> for Ratio<i128> {
687 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
688 float_cmp_shortcuts!(self, other);
689
690 let (man, exp, sign) = other.integer_decode();
692 let reverse = match (!self.is_negative(), sign >= 0) {
693 (true, false) => return Some(Ordering::Greater),
694 (false, true) => return Some(Ordering::Less),
695 (true, true) => false,
696 (false, false) => true,
697 };
698
699 let a = if self.numer() < &0 {
701 (*self.numer() as u128).wrapping_neg()
702 } else {
703 *self.numer() as u128
704 };
705 let b = if self.denom() < &0 {
706 (*self.denom() as u128).wrapping_neg()
707 } else {
708 *self.denom() as u128
709 };
710
711 let result = if exp >= 0 {
712 if let Some(num) = || -> Option<_> {
714 1u128
715 .checked_shl(exp as u32)?
716 .checked_mul(man as u128)?
717 .checked_mul(b)
718 }() {
719 a.partial_cmp(&num).unwrap()
720 } else {
721 Ordering::Less
722 }
723 } else {
724 let den = udouble::widening_mul(man as u128, b);
726 if let Some(num) = || -> Option<_> {
727 let (v, o) = udouble { lo: 1, hi: 0 }
728 .checked_shl((-exp) as u32)?
729 .overflowing_mul1(a);
730 if !o {
731 Some(v)
732 } else {
733 None
734 }
735 }() {
736 num.partial_cmp(&den).unwrap()
737 } else {
738 Ordering::Greater
739 }
740 };
741
742 if reverse {
743 Some(result.reverse())
744 } else {
745 Some(result)
746 }
747 }
748 }
749 impl_ord_by_swap!(f64|Ratio<i64>; f64|Ratio<u64>; f64|Ratio<i128>; f64|Ratio<u128>;);
750
751 macro_rules! impl_ratio_ord_with_floats_by_casting {
753 ($($float:ty => $bfloat:ty | $int:ty => $bint:ty;)*) => ($(
754 impl NumOrd<$float> for Ratio<$int> {
755 #[inline]
756 fn num_partial_cmp(&self, other: &$float) -> Option<Ordering> {
757 let bratio = Ratio::<$bint>::new(*self.numer() as $bint, *self.denom() as $bint);
758 bratio.num_partial_cmp(&(*other as $bfloat))
759 }
760 }
761 impl NumOrd<Ratio<$int>> for $float {
762 #[inline]
763 fn num_partial_cmp(&self, other: &Ratio<$int>) -> Option<Ordering> {
764 let bratio = Ratio::<$bint>::new(*other.numer() as $bint, *other.denom() as $bint);
765 (*self as $bfloat).num_partial_cmp(&bratio)
766 }
767 }
768 )*);
769 }
770 impl_ratio_ord_with_floats_by_casting! {
771 f32 => f64|i8 => i64; f32 => f64|i16 => i64; f32 => f64|i32 => i64; f32 => f64|i64 => i64;
772 f64 => f64|i8 => i64; f64 => f64|i16 => i64; f64 => f64|i32 => i64;
773 f32 => f64|u8 => u64; f32 => f64|u16 => u64; f32 => f64|u32 => u64; f32 => f64|u64 => u64;
774 f64 => f64|u8 => u64; f64 => f64|u16 => u64; f64 => f64|u32 => u64;
775 f32 => f64|u128 => u128; f32 => f64|i128 => i128;
776 }
777
778 macro_rules! impl_ratio_with_size_types_ord {
780 ($($t:ty)*) => ($(
781 impl NumOrd<$t> for Ratio<isize> {
782 #[inline]
783 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
784 #[cfg(target_pointer_width = "32")]
785 let r = Ratio::<i32>::new(*self.numer() as i32, *self.denom() as i32);
786 #[cfg(target_pointer_width = "64")]
787 let r = Ratio::<i64>::new(*self.numer() as i64, *self.denom() as i64);
788
789 r.num_partial_cmp(other)
790 }
791 }
792 impl NumOrd<$t> for Ratio<usize> {
793 #[inline]
794 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
795 #[cfg(target_pointer_width = "32")]
796 let r = Ratio::<u32>::new(*self.numer() as u32, *self.denom() as u32);
797 #[cfg(target_pointer_width = "64")]
798 let r = Ratio::<u64>::new(*self.numer() as u64, *self.denom() as u64);
799
800 r.num_partial_cmp(other)
801 }
802 }
803 impl_ord_by_swap!($t|Ratio<isize>; $t|Ratio<usize>;);
804 )*);
805 }
806 impl_ratio_with_size_types_ord!(i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64);
807
808 macro_rules! impl_ratio_ord_with_size_types {
809 ($($t:ty)*) => ($(
810 impl NumOrd<Ratio<$t>> for isize {
811 #[inline]
812 fn num_partial_cmp(&self, other: &Ratio<$t>) -> Option<Ordering> {
813 #[cfg(target_pointer_width = "32")]
814 return (*self as i32).num_partial_cmp(other);
815 #[cfg(target_pointer_width = "64")]
816 return (*self as i64).num_partial_cmp(other);
817 }
818 }
819 impl NumOrd<Ratio<$t>> for usize {
820 #[inline]
821 fn num_partial_cmp(&self, other: &Ratio<$t>) -> Option<Ordering> {
822 #[cfg(target_pointer_width = "32")]
823 return (*self as u32).num_partial_cmp(other);
824 #[cfg(target_pointer_width = "64")]
825 return (*self as u64).num_partial_cmp(other);
826 }
827 }
828 impl NumOrd<Ratio<$t>> for Ratio<isize> {
829 #[inline]
830 fn num_partial_cmp(&self, other: &Ratio<$t>) -> Option<Ordering> {
831 #[cfg(target_pointer_width = "32")]
832 let r = Ratio::<i32>::new(*self.numer() as i32, *self.denom() as i32);
833 #[cfg(target_pointer_width = "64")]
834 let r = Ratio::<i64>::new(*self.numer() as i64, *self.denom() as i64);
835
836 r.num_partial_cmp(other)
837 }
838 }
839 impl NumOrd<Ratio<$t>> for Ratio<usize> {
840 #[inline]
841 fn num_partial_cmp(&self, other: &Ratio<$t>) -> Option<Ordering> {
842 #[cfg(target_pointer_width = "32")]
843 let r = Ratio::<u32>::new(*self.numer() as u32, *self.denom() as u32);
844 #[cfg(target_pointer_width = "64")]
845 let r = Ratio::<u64>::new(*self.numer() as u64, *self.denom() as u64);
846
847 r.num_partial_cmp(other)
848 }
849 }
850 impl_ord_by_swap!(Ratio<$t>|isize; Ratio<$t>|usize; Ratio<$t>|Ratio<isize>; Ratio<$t>|Ratio<usize>;);
851 )*);
852 }
853 impl_ratio_ord_with_size_types!(i8 i16 i32 i64 i128 u8 u16 u32 u64 u128);
854
855 #[cfg(feature = "num-bigint")]
856 mod _num_bigint {
857 use super::*;
858 use num_bigint::{BigInt, BigUint};
859 use num_traits::One;
860
861 impl_ord_equal_types!(Ratio<BigInt> Ratio<BigUint>);
862 impl_ratio_ord_by_casting! {
863 u8 => BigUint; u16 => BigUint; u32 => BigUint; u64 => BigUint; u128 => BigUint;
864 i8 => BigInt; i16 => BigInt; i32 => BigInt; i64 => BigInt; i128 => BigInt;
865 u8 => BigInt; u16 => BigInt; u32 => BigInt; u64 => BigInt; u128 => BigInt;
866 }
867 impl_ratio_ord_between_diff_sign! {
868 i8 => BigUint; i16 => BigUint; i32 => BigUint; i64 => BigUint; i128 => BigUint;
869 }
870 impl_ratio_ord_with_int!(BigInt BigUint);
871 impl_ratio_with_size_types_ord!(BigInt BigUint);
872 impl_ratio_ord_with_size_types!(BigInt BigUint);
873
874 impl NumOrd<f64> for Ratio<BigUint> {
876 #[inline]
877 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
878 if self.is_zero() {
880 return 0f64.partial_cmp(other);
881 }
882 if other.is_zero() {
883 return self.numer().partial_cmp(&BigUint::zero());
884 }
885
886 if other.is_nan() {
888 return None;
889 } else if other.is_infinite() {
890 if other.is_sign_positive() {
891 return Some(Ordering::Less);
892 } else {
893 return Some(Ordering::Greater);
895 }
896 }
897
898 let (man, exp, sign) = other.integer_decode();
900 if sign < 0 {
901 return Some(Ordering::Greater);
902 }
903
904 let a = self.numer();
906 let b = self.denom();
907
908 let result = if exp >= 0 {
909 a.partial_cmp(&((BigUint::one() << exp as u32) * man))
911 .unwrap()
912 } else {
913 let den = BigUint::from(man) * b;
915 let num = (BigUint::one() << ((-exp) as u32)) * a;
916 num.partial_cmp(&den).unwrap()
917 };
918
919 Some(result)
920 }
921 }
922 impl NumOrd<f64> for Ratio<BigInt> {
923 #[inline]
924 fn num_partial_cmp(&self, other: &f64) -> Option<Ordering> {
925 if self.is_zero() {
927 return 0f64.partial_cmp(other);
928 }
929 if other.is_zero() {
930 return self.numer().partial_cmp(&BigInt::zero());
931 }
932
933 if other.is_nan() {
935 return None;
936 } else if other.is_infinite() {
937 if other.is_sign_positive() {
938 return Some(Ordering::Less);
939 } else {
940 return Some(Ordering::Greater);
942 }
943 }
944
945 let (man, exp, sign) = other.integer_decode();
947 let reverse = match (!self.is_negative(), sign >= 0) {
948 (true, false) => return Some(Ordering::Greater),
949 (false, true) => return Some(Ordering::Less),
950 (true, true) => false,
951 (false, false) => true,
952 };
953
954 let a = self.numer().magnitude();
956 let b = self.denom().magnitude();
957
958 let result = if exp >= 0 {
959 a.partial_cmp(&((BigUint::one() << exp as u32) * man))
961 .unwrap()
962 } else {
963 let den = BigUint::from(man) * b;
965 let num = (BigUint::one() << ((-exp) as u32)) * a;
966 num.partial_cmp(&den).unwrap()
967 };
968
969 if reverse {
970 Some(result.reverse())
971 } else {
972 Some(result)
973 }
974 }
975 }
976 impl NumOrd<f32> for Ratio<BigUint> {
977 #[inline]
978 fn num_partial_cmp(&self, other: &f32) -> Option<Ordering> {
979 self.num_partial_cmp(&(*other as f64))
980 }
981 }
982 impl NumOrd<f32> for Ratio<BigInt> {
983 #[inline]
984 fn num_partial_cmp(&self, other: &f32) -> Option<Ordering> {
985 self.num_partial_cmp(&(*other as f64))
986 }
987 }
988 impl NumOrd<Ratio<BigInt>> for Ratio<BigUint> {
989 #[inline]
990 fn num_partial_cmp(&self, other: &Ratio<BigInt>) -> Option<Ordering> {
991 if other.is_negative() {
992 Some(Ordering::Greater)
993 } else {
994 let rnum = other.numer().magnitude();
995 let rden = other.denom().magnitude();
996 (self.numer() * rden).partial_cmp(&(self.denom() * rnum))
997 }
998 }
999 }
1000 impl NumOrd<Ratio<BigInt>> for BigUint {
1001 #[inline]
1002 fn num_partial_cmp(&self, other: &Ratio<BigInt>) -> Option<Ordering> {
1003 if other.is_negative() {
1004 Some(Ordering::Greater)
1005 } else {
1006 let rnum = other.numer().magnitude();
1007 let rden = other.denom().magnitude();
1008 (self * rden).partial_cmp(&rnum)
1009 }
1010 }
1011 }
1012 impl_ord_by_swap! {
1013 f32|Ratio<BigInt>; f32|Ratio<BigUint>;
1014 f64|Ratio<BigInt>; f64|Ratio<BigUint>;
1015 Ratio<BigInt>|Ratio<BigUint>; Ratio<BigInt>|BigUint;
1016 }
1017 }
1018}
1019
1020#[cfg(feature = "num-complex")]
1022mod _num_complex {
1023 use super::*;
1024 use num_complex::{Complex, Complex32, Complex64};
1025
1026 macro_rules! impl_complex_ord_lexical {
1027 ($($t1:ty | $t2:ty;)*) => ($(
1028 impl NumOrd<Complex<$t2>> for Complex<$t1> {
1029 #[inline]
1030 fn num_partial_cmp(&self, other: &Complex<$t2>) -> Option<Ordering> {
1031 let re_cmp = self.re.num_partial_cmp(&other.re);
1032 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1033 self.im.num_partial_cmp(&other.im)
1034 } else {
1035 re_cmp
1036 }
1037 }
1038 }
1039 )*);
1040 ($($t:ty)*) => ($(
1041 impl NumOrd<Complex<$t>> for Complex<$t> {
1042 #[inline]
1043 fn num_partial_cmp(&self, other: &Complex<$t>) -> Option<Ordering> {
1044 let re_cmp = self.re.partial_cmp(&other.re);
1045 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1046 self.im.partial_cmp(&other.im)
1047 } else {
1048 re_cmp
1049 }
1050 }
1051 }
1052 )*);
1053 }
1054 impl_complex_ord_lexical!(f32 f64);
1055 impl_complex_ord_lexical!(f32|f64; f64|f32;);
1056
1057 macro_rules! impl_complex_ord_with_real {
1058 ($($t:ty)*) => ($(
1059 impl NumOrd<$t> for Complex32 {
1060 #[inline]
1061 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
1062 if self.im.is_nan() { return None;
1064 }
1065
1066 let re_cmp = self.re.num_partial_cmp(other);
1067 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1068 self.im.num_partial_cmp(&0f32)
1069 } else {
1070 re_cmp
1071 }
1072 }
1073 }
1074 impl NumOrd<Complex32> for $t {
1075 #[inline]
1076 fn num_partial_cmp(&self, other: &Complex32) -> Option<Ordering> {
1077 if other.im.is_nan() { return None;
1079 }
1080
1081 let re_cmp = self.num_partial_cmp(&other.re);
1082 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1083 0f32.num_partial_cmp(&other.im)
1084 } else {
1085 re_cmp
1086 }
1087 }
1088 }
1089 impl NumOrd<$t> for Complex64 {
1090 #[inline]
1091 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
1092 if self.im.is_nan() { return None;
1094 }
1095
1096 let re_cmp = self.re.num_partial_cmp(other);
1097 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1098 self.im.num_partial_cmp(&0f64)
1099 } else {
1100 re_cmp
1101 }
1102 }
1103 }
1104 impl NumOrd<Complex64> for $t {
1105 #[inline]
1106 fn num_partial_cmp(&self, other: &Complex64) -> Option<Ordering> {
1107 if other.im.is_nan() { return None;
1109 }
1110
1111 let re_cmp = self.num_partial_cmp(&other.re);
1112 if matches!(re_cmp, Some(o) if o == Ordering::Equal) {
1113 0f64.num_partial_cmp(&other.im)
1114 } else {
1115 re_cmp
1116 }
1117 }
1118 }
1119 )*);
1120 }
1121 impl_complex_ord_with_real! (
1122 i8 i16 i32 i64 i128 isize
1123 u8 u16 u32 u64 u128 usize
1124 f32 f64
1125 );
1126
1127 #[cfg(feature = "num-bigint")]
1128 mod _num_bigint {
1129 use super::*;
1130 use num_bigint::{BigInt, BigUint};
1131 impl_complex_ord_with_real! (
1132 BigInt BigUint
1133 );
1134 }
1135
1136 #[cfg(feature = "num-rational")]
1137 mod _num_rational {
1138 use super::*;
1139 use num_rational::Ratio;
1140 impl_complex_ord_with_real! (
1141 Ratio<i8> Ratio<i16> Ratio<i32> Ratio<i64> Ratio<i128> Ratio<isize>
1142 );
1143
1144 #[cfg(feature = "num-bigint")]
1145 mod _num_bigint {
1146 use super::*;
1147 use num_bigint::{BigInt, BigUint};
1148 impl_complex_ord_with_real! (
1149 Ratio<BigInt> Ratio<BigUint>
1150 );
1151 }
1152 }
1153}