@@ -41,7 +41,14 @@ const MAN_MASK: u64 = 0x000fffffffffffffu64;
41
41
42
42
// canonical raw bit patterns (for hashing)
43
43
const 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
+ }
45
52
46
53
/// A wrapper around floats providing implementations of `Eq`, `Ord`, and `Hash`.
47
54
///
@@ -116,25 +123,43 @@ impl<T: FloatCore> PartialOrd for OrderedFloat<T> {
116
123
fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
117
124
Some ( self . cmp ( other) )
118
125
}
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
+ }
119
151
}
120
152
121
153
impl < T : FloatCore > Ord for OrderedFloat < T > {
154
+ #[ inline]
122
155
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
138
163
}
139
164
}
140
165
}
@@ -161,10 +186,8 @@ impl<T: FloatCore> Hash for OrderedFloat<T> {
161
186
fn hash < H : Hasher > ( & self , state : & mut H ) {
162
187
let bits = if self . is_nan ( ) {
163
188
CANONICAL_NAN_BITS
164
- } else if self . is_zero ( ) {
165
- CANONICAL_ZERO_BITS
166
189
} else {
167
- raw_double_bits ( & self . 0 )
190
+ raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) )
168
191
} ;
169
192
170
193
bits. hash ( state)
@@ -1150,12 +1173,7 @@ impl<T: FloatCore> Ord for NotNan<T> {
1150
1173
impl < T : FloatCore > Hash for NotNan < T > {
1151
1174
#[ inline]
1152
1175
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 ) ) ;
1159
1177
bits. hash ( state)
1160
1178
}
1161
1179
}
0 commit comments