Skip to content

Commit

Permalink
fix hash(::BigInt) on 32 bit systems (#50076)
Browse files Browse the repository at this point in the history
* don't define hash(::BigInt) on 32 bit systems
  • Loading branch information
oscardssmith authored Jun 6, 2023
1 parent 4d2f35e commit c3ea5dc
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 16 deletions.
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

0 comments on commit c3ea5dc

Please sign in to comment.