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 hash(::BigInt) on 32 bit systems #50076

Merged
merged 5 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 6 additions & 9 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -843,8 +843,8 @@ Base.deepcopy_internal(x::BigInt, stackdict::IdDict) = get!(() -> MPZ.set(x), st

## streamlined hashing for BigInt, by avoiding allocation from shifts ##

if Limb === UInt
# this condition is true most (all?) of the time, and in this case we can define
if Limb === UInt64 === UInt
# On 64 bit systems we can define
# an optimized version for BigInt of hash_integer (used e.g. for Rational{BigInt}),
# and of hash

Expand All @@ -854,7 +854,7 @@ if Limb === UInt
GC.@preserve n begin
s = n.size
s == 0 && return hash_integer(0, h)
p = convert(Ptr{UInt}, n.d)
p = convert(Ptr{UInt64}, n.d)
b = unsafe_load(p)
h ⊻= hash_uint(ifelse(s < 0, -b, b) ⊻ h)
for k = 2:abs(s)
Expand All @@ -864,14 +864,11 @@ if Limb === UInt
end
end

_divLimb(n) = UInt === UInt64 ? n >>> 6 : n >>> 5
_modLimb(n) = UInt === UInt64 ? n & 63 : n & 31

function hash(x::BigInt, h::UInt)
GC.@preserve x begin
sz = x.size
sz == 0 && return hash(0, h)
ptr = Ptr{UInt}(x.d)
ptr = Ptr{UInt64}(x.d)
if sz == 1
return hash(unsafe_load(ptr), h)
elseif sz == -1
Expand All @@ -880,8 +877,8 @@ if Limb === UInt
end
pow = trailing_zeros(x)
nd = Base.ndigits0z(x, 2)
idx = _divLimb(pow) + 1
shift = _modLimb(pow) % UInt
idx = (pow >>> 6) + 1
shift = (pow & 63) % UInt
upshift = BITS_PER_LIMB - shift
asz = abs(sz)
if shift == 0
Expand Down
9 changes: 2 additions & 7 deletions test/hashing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,8 @@ types = Any[
Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64,
Rational{Int8}, Rational{UInt8}, Rational{Int16}, Rational{UInt16},
Rational{Int32}, Rational{UInt32}, Rational{Int64}, Rational{UInt64},
BigFloat, #BigInt, # TODO: BigInt hashing is broken on 32-bit systems
BigFloat, BigInt, Rational{BigInt}
]
if Int === Int64
push!(types, BigInt)
else
@test_broken hash(12345678901234) == hash(big(12345678901234))
end
vals = vcat(
typemin(Int64),
-Int64(maxintfloat(Float64)) .+ Int64[-4:1;],
Expand Down Expand Up @@ -57,7 +52,7 @@ let collides = 0
collides += eq
end
end
@test collides <= 452
@test collides <= 516
end
@test hash(0.0) != hash(-0.0)

Expand Down