@@ -42,7 +42,14 @@ const MAN_MASK: u64 = 0x000fffffffffffffu64;
42
42
43
43
// canonical raw bit patterns (for hashing)
44
44
const CANONICAL_NAN_BITS : u64 = 0x7ff8000000000000u64 ;
45
- const CANONICAL_ZERO_BITS : u64 = 0x0u64 ;
45
+
46
+ #[ inline( always) ]
47
+ fn canonicalize_signed_zero < T : Float > ( x : T ) -> T {
48
+ // -0.0 + 0.0 == +0.0 under IEEE754 roundTiesToEven rounding mode,
49
+ // which Rust guarantees. Thus by adding a positive zero we
50
+ // canonicalize signed zero without any branches in one instruction.
51
+ x + T :: zero ( )
52
+ }
46
53
47
54
/// A wrapper around floats providing implementations of `Eq`, `Ord`, and `Hash`.
48
55
///
@@ -174,10 +181,8 @@ impl<T: Float> Hash for OrderedFloat<T> {
174
181
fn hash < H : Hasher > ( & self , state : & mut H ) {
175
182
let bits = if self . is_nan ( ) {
176
183
CANONICAL_NAN_BITS
177
- } else if self . is_zero ( ) {
178
- CANONICAL_ZERO_BITS
179
184
} else {
180
- raw_double_bits ( & self . 0 )
185
+ raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) )
181
186
} ;
182
187
183
188
bits. hash ( state)
@@ -1163,12 +1168,7 @@ impl<T: Float> Ord for NotNan<T> {
1163
1168
impl < T : Float > Hash for NotNan < T > {
1164
1169
#[ inline]
1165
1170
fn hash < H : Hasher > ( & self , state : & mut H ) {
1166
- let bits = if self . is_zero ( ) {
1167
- CANONICAL_ZERO_BITS
1168
- } else {
1169
- raw_double_bits ( & self . 0 )
1170
- } ;
1171
-
1171
+ let bits = raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) ) ;
1172
1172
bits. hash ( state)
1173
1173
}
1174
1174
}
0 commit comments