@@ -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
///
@@ -173,10 +180,8 @@ impl<T: FloatCore> Hash for OrderedFloat<T> {
173
180
fn hash < H : Hasher > ( & self , state : & mut H ) {
174
181
let bits = if self . is_nan ( ) {
175
182
CANONICAL_NAN_BITS
176
- } else if self . is_zero ( ) {
177
- CANONICAL_ZERO_BITS
178
183
} else {
179
- raw_double_bits ( & self . 0 )
184
+ raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) )
180
185
} ;
181
186
182
187
bits. hash ( state)
@@ -1162,12 +1167,7 @@ impl<T: FloatCore> Ord for NotNan<T> {
1162
1167
impl < T : FloatCore > Hash for NotNan < T > {
1163
1168
#[ inline]
1164
1169
fn hash < H : Hasher > ( & self , state : & mut H ) {
1165
- let bits = if self . is_zero ( ) {
1166
- CANONICAL_ZERO_BITS
1167
- } else {
1168
- raw_double_bits ( & self . 0 )
1169
- } ;
1170
-
1170
+ let bits = raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) ) ;
1171
1171
bits. hash ( state)
1172
1172
}
1173
1173
}
0 commit comments