about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-05-29 20:21:18 +0200
committerGitHub <noreply@github.com>2020-05-29 20:21:18 +0200
commitc09f0eb3eb7ca092fdaeacab37bf05fea1e241f8 (patch)
tree3ca519557c5cbc3e0405a3f1beecc02681e6f5d4 /src/libstd
parent9ef62271170cd15a8cbfa8d1d6192d1302e9cce2 (diff)
parent66da7350963edf3d40461e6f5bafde95974908fc (diff)
downloadrust-c09f0eb3eb7ca092fdaeacab37bf05fea1e241f8.tar.gz
rust-c09f0eb3eb7ca092fdaeacab37bf05fea1e241f8.zip
Rollup merge of #72568 - golddranks:add_total_cmp_to_floats, r=sfackler
Implement total_cmp for f32, f64

# Overview
* Implements method `total_cmp` on `f32` and `f64`. This method implements a float comparison that, unlike the standard `partial_cmp`, is total (defined on all values) in accordance to the IEEE 754 (rev 2008) §5.10 `totalOrder` predicate.
* The method has an API similar to `cmp`: `pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { ... }`.
* Implements tests.
* Has documentation.

# Justification for the API
* Total ordering for `f32` and `f64` has been discussed many time before:
  * https://internals.rust-lang.org/t/pre-pre-rfc-range-restricting-wrappers-for-floating-point-types/6701
  * https://github.com/rust-lang/rfcs/issues/1249
  * https://github.com/rust-lang/rust/pull/53938
  * https://github.com/rust-lang/rust/issues/5585
* The lack of total ordering leads to frequent complaints, especially from people new to Rust.
  * This is an ergonomics issue that needs to be addressed.
  * However, the default behaviour of implementing only `PartialOrd` is intentional, as relaxing it might lead to correctness issues.
* Most earlier implementations and discussions have been focusing on a wrapper type that implements trait `Ord`. Such a wrapper type is, however not easy to add because of the large API surface added.
* As a minimal step that hopefully proves uncontroversial, we can implement a stand-alone method `total_cmp` on floating point types.
  * I expect adding such methods should be uncontroversial because...
    * Similar methods on `f32` and `f64` would be warranted even in case stdlib would provide a wrapper type that implements `Ord` some day.
    * It implements functionality that is standardised. (IEEE 754, 2008 rev. §5.10 Note, that the 2019 revision relaxes the ordering. The way we do ordering in this method conforms to the stricter 2008 standard.)
* With stdlib APIs such as `slice::sort_by` and `slice::binary_search_by` that allow users to provide a custom ordering criterion, providing additional helper methods is a minimal way of adding ordering functionality.
  * Not also does it allow easily using aforementioned APIs, it also provides an easy and well-tested primitive for the users and library authors to implement an `Ord`-implementing wrapper, if needed.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/f32.rs143
-rw-r--r--src/libstd/f64.rs143
-rw-r--r--src/libstd/lib.rs1
3 files changed, 287 insertions, 0 deletions
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index deb9eb5b4b0..8ff19557a30 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -1531,4 +1531,147 @@ mod tests {
     fn test_clamp_max_is_nan() {
         let _ = 1.0f32.clamp(3.0, NAN);
     }
+
+    #[test]
+    fn test_total_cmp() {
+        use core::cmp::Ordering;
+
+        fn quiet_bit_mask() -> u32 {
+            1 << (f32::MANTISSA_DIGITS - 2)
+        }
+
+        fn min_subnorm() -> f32 {
+            f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
+        }
+
+        fn max_subnorm() -> f32 {
+            f32::MIN_POSITIVE - min_subnorm()
+        }
+
+        fn q_nan() -> f32 {
+            f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
+        }
+
+        fn s_nan() -> f32 {
+            f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
+        }
+
+        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
+        assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
+        assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
+        assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
+        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
+        assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
+        assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
+        assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
+        assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
+        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
+        assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
+        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
+        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
+        assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
+        assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
+    }
 }
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index b79e550ed26..d7845fd2c4d 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -1554,4 +1554,147 @@ mod tests {
     fn test_clamp_max_is_nan() {
         let _ = 1.0f64.clamp(3.0, NAN);
     }
+
+    #[test]
+    fn test_total_cmp() {
+        use core::cmp::Ordering;
+
+        fn quiet_bit_mask() -> u64 {
+            1 << (f64::MANTISSA_DIGITS - 2)
+        }
+
+        fn min_subnorm() -> f64 {
+            f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
+        }
+
+        fn max_subnorm() -> f64 {
+            f64::MIN_POSITIVE - min_subnorm()
+        }
+
+        fn q_nan() -> f64 {
+            f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
+        }
+
+        fn s_nan() -> f64 {
+            f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
+        }
+
+        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
+        assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
+        assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
+        assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
+        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
+        assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
+        assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
+        assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
+        assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
+        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
+        assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
+        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
+        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
+        assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
+        assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
+    }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index cc3e613fa3d..72dfe2937f4 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -311,6 +311,7 @@
 #![feature(test)]
 #![feature(thread_local)]
 #![feature(toowned_clone_into)]
+#![feature(total_cmp)]
 #![feature(trace_macros)]
 #![feature(track_caller)]
 #![feature(try_reserve)]