Skip to content

Commit

Permalink
Optimize top_set_bit(::BigInt) and hash(::Real) (#49996)
Browse files Browse the repository at this point in the history
* implement top_set_bit in Julia for increased performance

* simplify and optimize hash(::Real)

---------

Co-authored-by: Lilith Hafner <Lilith.Hafner@gmail.com>
  • Loading branch information
LilithHafner and Lilith Hafner authored Jun 2, 2023
1 parent f09e46d commit 1961019
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 20 deletions.
28 changes: 11 additions & 17 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -674,34 +674,28 @@ function hash(x::Real, h::UInt)
num = -num
den = -den
end
z = trailing_zeros(num)
if z != 0
num >>= z
pow += z
end
z = trailing_zeros(den)
if z != 0
den >>= z
pow -= z
end
num_z = trailing_zeros(num)
den_z = trailing_zeros(den)
den >>= den_z
pow += num_z - den_z

# handle values representable as Int64, UInt64, Float64
if den == 1
left = ndigits0z(num,2) + pow
right = trailing_zeros(num) + pow
left = top_set_bit(abs(num)) - den_z
right = pow
if -1074 <= right
if 0 <= right && left <= 64
left <= 63 && return hash(Int64(num) << Int(pow), h)
signbit(num) == signbit(den) && return hash(UInt64(num) << Int(pow), h)
if 0 <= right
left <= 63 && return hash(Int64(num) << Int(pow-num_z), h)
left <= 64 && !signbit(num) && return hash(UInt64(num) << Int(pow-num_z), h)
end # typemin(Int64) handled by Float64 case
left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num),pow), h)
left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num), pow-num_z), h)
end
end

# handle generic rational values
h = hash_integer(den, h)
h = hash_integer(pow, h)
h = hash_integer(num, h)
h = hash_integer(num >> num_z, h)
return h
end

Expand Down
6 changes: 3 additions & 3 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -606,9 +606,9 @@ Number of ones in the binary representation of abs(x).
count_ones_abs(x::BigInt) = iszero(x) ? 0 : MPZ.mpn_popcount(x)

function top_set_bit(x::BigInt)
x < 0 && throw(DomainError(x, "top_set_bit only supports negative arguments when they have type BitSigned."))
x == 0 && return 0
Int(ccall((:__gmpz_sizeinbase, :libgmp), Csize_t, (Base.GMP.MPZ.mpz_t, Cint), x, 2))
isneg(x) && throw(DomainError(x, "top_set_bit only supports negative arguments when they have type BitSigned."))
iszero(x) && return 0
x.size * sizeof(Limb) << 3 - leading_zeros(GC.@preserve x unsafe_load(x.d, x.size))
end

divrem(x::BigInt, y::BigInt) = MPZ.tdiv_qr(x, y)
Expand Down

2 comments on commit 1961019

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily package evaluation, I will reply here when finished:

@nanosoldier runtests(isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your package evaluation job has completed - possible new issues were detected.
A full report can be found here.

Please sign in to comment.