@@ -810,4 +810,78 @@ impl f32 {
810
810
pub fn from_ne_bytes ( bytes : [ u8 ; 4 ] ) -> Self {
811
811
Self :: from_bits ( u32:: from_ne_bytes ( bytes) )
812
812
}
813
+
814
+ /// Returns an ordering between self and other values.
815
+ /// Unlike the standard partial comparison between floating point numbers,
816
+ /// this comparison always produces an ordering in accordance to
817
+ /// the totalOrder predicate as defined in IEEE 754 (2008 revision)
818
+ /// floating point standard. The values are ordered in following order:
819
+ /// - Negative quiet NaN
820
+ /// - Negative signaling NaN
821
+ /// - Negative infinity
822
+ /// - Negative numbers
823
+ /// - Negative subnormal numbers
824
+ /// - Negative zero
825
+ /// - Positive zero
826
+ /// - Positive subnormal numbers
827
+ /// - Positive numbers
828
+ /// - Positive infinity
829
+ /// - Positive signaling NaN
830
+ /// - Positive quiet NaN
831
+ ///
832
+ /// # Example
833
+ /// ```
834
+ /// #![feature(total_cmp)]
835
+ /// struct GoodBoy {
836
+ /// name: String,
837
+ /// weight: f32,
838
+ /// }
839
+ ///
840
+ /// let mut bois = vec![
841
+ /// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
842
+ /// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
843
+ /// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
844
+ /// GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY },
845
+ /// GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
846
+ /// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
847
+ /// ];
848
+ ///
849
+ /// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
850
+ /// # assert!(bois.into_iter().map(|b| b.weight)
851
+ /// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
852
+ /// # .all(|(a, b)| a.to_bits() == b.to_bits()))
853
+ /// ```
854
+ #[ unstable( feature = "total_cmp" , issue = "72599" ) ]
855
+ #[ inline]
856
+ pub fn total_cmp ( & self , other : & Self ) -> crate :: cmp:: Ordering {
857
+ let mut left = self . to_bits ( ) as i32 ;
858
+ let mut right = other. to_bits ( ) as i32 ;
859
+
860
+ // In case of negatives, flip all the bits except the sign
861
+ // to achieve a similar layout as two's complement integers
862
+ //
863
+ // Why does this work? IEEE 754 floats consist of three fields:
864
+ // Sign bit, exponent and mantissa. The set of exponent and mantissa
865
+ // fields as a whole have the property that their bitwise order is
866
+ // equal to the numeric magnitude where the magnitude is defined.
867
+ // The magnitude is not normally defined on NaN values, but
868
+ // IEEE 754 totalOrder defines the NaN values also to follow the
869
+ // bitwise order. This leads to order explained in the doc comment.
870
+ // However, the representation of magnitude is the same for negative
871
+ // and positive numbers – only the sign bit is different.
872
+ // To easily compare the floats as signed integers, we need to
873
+ // flip the exponent and mantissa bits in case of negative numbers.
874
+ // We effectively convert the numbers to "two's complement" form.
875
+ //
876
+ // To do the flipping, we construct a mask and XOR against it.
877
+ // We branchlessly calculate an "all-ones except for the sign bit"
878
+ // mask from negative-signed values: right shifting sign-extends
879
+ // the integer, so we "fill" the mask with sign bits, and then
880
+ // convert to unsigned to push one more zero bit.
881
+ // On positive values, the mask is all zeros, so it's a no-op.
882
+ left ^= ( ( ( left >> 31 ) as u32 ) >> 1 ) as i32 ;
883
+ right ^= ( ( ( right >> 31 ) as u32 ) >> 1 ) as i32 ;
884
+
885
+ left. cmp ( & right)
886
+ }
813
887
}
0 commit comments