@@ -41,7 +41,14 @@ const MAN_MASK: u64 = 0x000fffffffffffffu64;
4141
4242// canonical raw bit patterns (for hashing)
4343const CANONICAL_NAN_BITS : u64 = 0x7ff8000000000000u64 ;
44- const CANONICAL_ZERO_BITS : u64 = 0x0u64 ;
44+
45+ #[ inline( always) ]
46+ fn canonicalize_signed_zero < T : FloatCore > ( x : T ) -> T {
47+ // -0.0 + 0.0 == +0.0 under IEEE754 roundTiesToEven rounding mode,
48+ // which Rust guarantees. Thus by adding a positive zero we
49+ // canonicalize signed zero without any branches in one instruction.
50+ x + T :: zero ( )
51+ }
4552
4653/// A wrapper around floats providing implementations of `Eq`, `Ord`, and `Hash`.
4754///
@@ -116,25 +123,43 @@ impl<T: FloatCore> PartialOrd for OrderedFloat<T> {
116123 fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
117124 Some ( self . cmp ( other) )
118125 }
126+
127+ #[ inline]
128+ fn lt ( & self , other : & Self ) -> bool {
129+ !self . ge ( other)
130+ }
131+
132+ #[ inline]
133+ fn le ( & self , other : & Self ) -> bool {
134+ other. ge ( self )
135+ }
136+
137+ #[ inline]
138+ fn gt ( & self , other : & Self ) -> bool {
139+ !other. ge ( self )
140+ }
141+
142+ #[ inline]
143+ fn ge ( & self , other : & Self ) -> bool {
144+ // We consider all NaNs equal, and NaN is the largest possible
145+ // value. Thus if self is NaN we always return true. Otherwise
146+ // self >= other is correct. If other is also not NaN it is trivially
147+ // correct, and if it is we note that nothing can be greater or
148+ // equal to NaN except NaN itself, which we already handled earlier.
149+ self . 0 . is_nan ( ) | ( self . 0 >= other. 0 )
150+ }
119151}
120152
121153impl < T : FloatCore > Ord for OrderedFloat < T > {
154+ #[ inline]
122155 fn cmp ( & self , other : & Self ) -> Ordering {
123- let lhs = & self . 0 ;
124- let rhs = & other. 0 ;
125- match lhs. partial_cmp ( rhs) {
126- Some ( ordering) => ordering,
127- None => {
128- if lhs. is_nan ( ) {
129- if rhs. is_nan ( ) {
130- Ordering :: Equal
131- } else {
132- Ordering :: Greater
133- }
134- } else {
135- Ordering :: Less
136- }
137- }
156+ #[ allow( clippy:: comparison_chain) ]
157+ if self < other {
158+ Ordering :: Less
159+ } else if self > other {
160+ Ordering :: Greater
161+ } else {
162+ Ordering :: Equal
138163 }
139164 }
140165}
@@ -161,10 +186,8 @@ impl<T: FloatCore> Hash for OrderedFloat<T> {
161186 fn hash < H : Hasher > ( & self , state : & mut H ) {
162187 let bits = if self . is_nan ( ) {
163188 CANONICAL_NAN_BITS
164- } else if self . is_zero ( ) {
165- CANONICAL_ZERO_BITS
166189 } else {
167- raw_double_bits ( & self . 0 )
190+ raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) )
168191 } ;
169192
170193 bits. hash ( state)
@@ -1150,12 +1173,7 @@ impl<T: FloatCore> Ord for NotNan<T> {
11501173impl < T : FloatCore > Hash for NotNan < T > {
11511174 #[ inline]
11521175 fn hash < H : Hasher > ( & self , state : & mut H ) {
1153- let bits = if self . is_zero ( ) {
1154- CANONICAL_ZERO_BITS
1155- } else {
1156- raw_double_bits ( & self . 0 )
1157- } ;
1158-
1176+ let bits = raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) ) ;
11591177 bits. hash ( state)
11601178 }
11611179}
0 commit comments