Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix hashing regression. #50655

Merged
merged 8 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -688,22 +688,24 @@ function hash(x::Real, h::UInt)
den_z = trailing_zeros(den)
den >>= den_z
pow += num_z - den_z

# handle values representable as Int64, UInt64, Float64
# If the real is an Int64, UInt64, or Float64, hash as those types.
oscardssmith marked this conversation as resolved.
Show resolved Hide resolved
# To be an Integer the denominator must be 1 and the power must be non-negative.
if den == 1
# left = ceil(log2(num*2^pow))
left = top_set_bit(abs(num)) + pow
right = pow + den_z
if -1074 <= right
if 0 <= right
# 2^-1074 is the minimum Float64 so if the power is smaller, not a Float64
if -1074 <= pow
oscardssmith marked this conversation as resolved.
Show resolved Hide resolved
if pow >= 0 # if pow is negative, it isn't an integer
oscardssmith marked this conversation as resolved.
Show resolved Hide resolved
left <= 63 && return hash(Int64(num) << Int(pow), h)
left <= 64 && !signbit(num) && return hash(UInt64(num) << Int(pow), h)
end # typemin(Int64) handled by Float64 case
left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num), pow), h)
# 2^1024 is the maximum Float64 so if the power is greater, not a Float64
oscardssmith marked this conversation as resolved.
Show resolved Hide resolved
# Float64s only have 53 mantisa bits (including implicit bit)
left <= 1024 && left - pow <= 53 && return hash(ldexp(Float64(num), pow), h)
end
else
h = hash_integer(den, h)
end

# handle generic rational values
h = hash_integer(pow, h)
h = hash_integer(num, h)
Expand Down
3 changes: 2 additions & 1 deletion base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,10 @@ function hash(x::Rational{<:BitInteger64}, h::UInt)
num, den = Base.numerator(x), Base.denominator(x)
den == 1 && return hash(num, h)
den == 0 && return hash(ifelse(num > 0, Inf, -Inf), h)
if isodd(den)
if isodd(den) # since den != 1, this rational can't be a Float64
pow = trailing_zeros(num)
num >>= pow
h = hash_integer(den, h)
else
pow = trailing_zeros(den)
den >>= pow
Expand Down
15 changes: 15 additions & 0 deletions test/hashing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,18 @@ struct AUnionParam{T<:Union{Nothing,Float32,Float64}} end
@test Type{AUnionParam{<:Union{Nothing,Float32,Float64}}} === Type{AUnionParam}
@test Type{AUnionParam.body}.hash == 0
@test Type{Base.Broadcast.Broadcasted}.hash != 0


@testset "issue 50628" begin
# test hashing of rationals that equal floats are equal to the float hash
@test hash(5//2) == hash(big(5)//2) == hash(2.5)
# test hashing of rational that are integers hash to the integer
@test hash(5^25) == hash(big(5)^25) == hash(5^25//1) == hash(big(5)^25//1)
# test integer/rational that don't fit in Float64 don't hash as Float64
@test hash(5^25) != hash(5.0^25)
@test hash((5//2)^25) == hash(big(5//2)^25)
# test integer/rational that don't fit in Float64 don't hash as Float64
@test hash((5//2)^25) != hash(2.5^25)
# test hashing of rational with odd denominator
@test hash(5//3) == hash(big(5)//3)
end