@@ -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///
@@ -173,10 +180,8 @@ impl<T: FloatCore> Hash for OrderedFloat<T> {
173180 fn hash < H : Hasher > ( & self , state : & mut H ) {
174181 let bits = if self . is_nan ( ) {
175182 CANONICAL_NAN_BITS
176- } else if self . is_zero ( ) {
177- CANONICAL_ZERO_BITS
178183 } else {
179- raw_double_bits ( & self . 0 )
184+ raw_double_bits ( & canonicalize_signed_zero ( self . 0 ) )
180185 } ;
181186
182187 bits. hash ( state)
@@ -1162,12 +1167,7 @@ impl<T: FloatCore> Ord for NotNan<T> {
11621167impl < T : FloatCore > Hash for NotNan < T > {
11631168 #[ inline]
11641169 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 ) ) ;
11711171 bits. hash ( state)
11721172 }
11731173}
0 commit comments