@@ -810,4 +810,78 @@ impl f32 {
810810 pub fn from_ne_bytes ( bytes : [ u8 ; 4 ] ) -> Self {
811811 Self :: from_bits ( u32:: from_ne_bytes ( bytes) )
812812 }
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+ }
813887}
0 commit comments