diff --git a/base/float.jl b/base/float.jl index eb30c087c0f8c..0f05027b522a2 100644 --- a/base/float.jl +++ b/base/float.jl @@ -674,34 +674,28 @@ function hash(x::Real, h::UInt) num = -num den = -den end - z = trailing_zeros(num) - if z != 0 - num >>= z - pow += z - end - z = trailing_zeros(den) - if z != 0 - den >>= z - pow -= z - end + num_z = trailing_zeros(num) + den_z = trailing_zeros(den) + den >>= den_z + pow += num_z - den_z # handle values representable as Int64, UInt64, Float64 if den == 1 - left = ndigits0z(num,2) + pow - right = trailing_zeros(num) + pow + left = top_set_bit(abs(num)) - den_z + right = pow if -1074 <= right - if 0 <= right && left <= 64 - left <= 63 && return hash(Int64(num) << Int(pow), h) - signbit(num) == signbit(den) && return hash(UInt64(num) << Int(pow), h) + if 0 <= right + left <= 63 && return hash(Int64(num) << Int(pow-num_z), h) + left <= 64 && !signbit(num) && return hash(UInt64(num) << Int(pow-num_z), h) end # typemin(Int64) handled by Float64 case - left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num),pow), h) + left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num), pow-num_z), h) end end # handle generic rational values h = hash_integer(den, h) h = hash_integer(pow, h) - h = hash_integer(num, h) + h = hash_integer(num >> num_z, h) return h end diff --git a/base/gmp.jl b/base/gmp.jl index 69926f4ad0d06..3f809fd99d1cc 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -606,9 +606,9 @@ Number of ones in the binary representation of abs(x). count_ones_abs(x::BigInt) = iszero(x) ? 0 : MPZ.mpn_popcount(x) function top_set_bit(x::BigInt) - x < 0 && throw(DomainError(x, "top_set_bit only supports negative arguments when they have type BitSigned.")) - x == 0 && return 0 - Int(ccall((:__gmpz_sizeinbase, :libgmp), Csize_t, (Base.GMP.MPZ.mpz_t, Cint), x, 2)) + isneg(x) && throw(DomainError(x, "top_set_bit only supports negative arguments when they have type BitSigned.")) + iszero(x) && return 0 + x.size * sizeof(Limb) << 3 - leading_zeros(GC.@preserve x unsafe_load(x.d, x.size)) end divrem(x::BigInt, y::BigInt) = MPZ.tdiv_qr(x, y)