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

(cherry picked from commit c3ea5dc)
  • Loading branch information
oscardssmith authored and KristofferC committed Jun 27, 2023
1 parent 9046323 commit 0857574
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 12 deletions.
15 changes: 6 additions & 9 deletions base/gmp.jl
Expand Up @@ -808,8 +808,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 @@ -819,7 +819,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 @@ -829,14 +829,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 @@ -845,8 +842,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
6 changes: 3 additions & 3 deletions test/hashing.jl
Expand Up @@ -8,7 +8,8 @@ types = Any[
Bool,
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}
Rational{Int32}, Rational{UInt32}, Rational{Int64}, Rational{UInt64},
BigFloat, BigInt, Rational{BigInt}
]
vals = vcat(
typemin(Int64),
Expand Down Expand Up @@ -51,8 +52,7 @@ let collides = 0
collides += eq
end
end
# each pair of types has one collision for these values
@test collides <= (length(types) - 1)^2
@test collides <= 516
end
@test hash(0.0) != hash(-0.0)

Expand Down

0 comments on commit 0857574

Please sign in to comment.