From 41bb9337aac3667811b577bf733bdc429fde50ae Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Tue, 6 Jun 2023 13:26:20 -0400 Subject: [PATCH] fix `hash(::BigInt)` on 32 bit systems (#50076) * don't define hash(::BigInt) on 32 bit systems (cherry picked from commit c3ea5dc9dc3f903a75107788858d20123bcfb0b4) --- base/gmp.jl | 15 ++++++--------- test/hashing.jl | 6 +++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/base/gmp.jl b/base/gmp.jl index 42979df0382c2..b881723832862 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -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 @@ -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) @@ -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 @@ -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 diff --git a/test/hashing.jl b/test/hashing.jl index 9f40e7a4a73ac..4ecadddb7542c 100644 --- a/test/hashing.jl +++ b/test/hashing.jl @@ -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), @@ -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)