Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
181
julia-0.6.2/share/julia/base/hashing2.jl
Normal file
181
julia-0.6.2/share/julia/base/hashing2.jl
Normal file
@@ -0,0 +1,181 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
## efficient value-based hashing of integers ##
|
||||
|
||||
function hash_integer(n::Integer, h::UInt)
|
||||
h ⊻= hash_uint((n % UInt) ⊻ h)
|
||||
n = abs(n)
|
||||
n >>>= sizeof(UInt) << 3
|
||||
while n != 0
|
||||
h ⊻= hash_uint((n % UInt) ⊻ h)
|
||||
n >>>= sizeof(UInt) << 3
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
function hash_integer(n::BigInt, h::UInt)
|
||||
s = n.size
|
||||
s == 0 && return hash_integer(0, h)
|
||||
p = convert(Ptr{UInt}, n.d)
|
||||
b = unsafe_load(p)
|
||||
h ⊻= hash_uint(ifelse(s < 0, -b, b) ⊻ h)
|
||||
for k = 2:abs(s)
|
||||
h ⊻= hash_uint(unsafe_load(p, k) ⊻ h)
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
## generic hashing for rational values ##
|
||||
|
||||
function hash(x::Real, h::UInt)
|
||||
# decompose x as num*2^pow/den
|
||||
num, pow, den = decompose(x)
|
||||
|
||||
# handle special values
|
||||
num == 0 && den == 0 && return hash(NaN, h)
|
||||
num == 0 && return hash(ifelse(den > 0, 0.0, -0.0), h)
|
||||
den == 0 && return hash(ifelse(num > 0, Inf, -Inf), h)
|
||||
|
||||
# normalize decomposition
|
||||
if den < 0
|
||||
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
|
||||
|
||||
# handle values representable as Int64, UInt64, Float64
|
||||
if den == 1
|
||||
left = ndigits0z(num,2) + pow
|
||||
right = trailing_zeros(num) + 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)
|
||||
end # typemin(Int64) handled by Float64 case
|
||||
left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num),pow), h)
|
||||
end
|
||||
end
|
||||
|
||||
# handle generic rational values
|
||||
h = hash_integer(den, h)
|
||||
h = hash_integer(pow, h)
|
||||
h = hash_integer(num, h)
|
||||
return h
|
||||
end
|
||||
|
||||
#=
|
||||
`decompose(x)`: non-canonical decomposition of rational values as `num*2^pow/den`.
|
||||
|
||||
The decompose function is the point where rational-valued numeric types that support
|
||||
hashing hook into the hashing protocol. `decompose(x)` should return three integer
|
||||
values `num, pow, den`, such that the value of `x` is mathematically equal to
|
||||
|
||||
num*2^pow/den
|
||||
|
||||
The decomposition need not be canonical in the sense that it just needs to be *some*
|
||||
way to express `x` in this form, not any particular way – with the restriction that
|
||||
`num` and `den` may not share any odd common factors. They may, however, have powers
|
||||
of two in common – the generic hashing code will normalize those as necessary.
|
||||
|
||||
Special values:
|
||||
|
||||
- `x` is zero: `num` should be zero and `den` should have the same sign as `x`
|
||||
- `x` is infinite: `den` should be zero and `num` should have the same sign as `x`
|
||||
- `x` is not a number: `num` and `den` should both be zero
|
||||
=#
|
||||
|
||||
decompose(x::Integer) = x, 0, 1
|
||||
decompose(x::Rational) = numerator(x), 0, denominator(x)
|
||||
|
||||
function decompose(x::Float16)::NTuple{3,Int}
|
||||
isnan(x) && return 0, 0, 0
|
||||
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
|
||||
n = reinterpret(UInt16, x)
|
||||
s = (n & 0x03ff) % Int16
|
||||
e = (n & 0x7c00 >> 10) % Int
|
||||
s |= Int16(e != 0) << 10
|
||||
d = ifelse(signbit(x), -1, 1)
|
||||
s, e - 25 + (e == 0), d
|
||||
end
|
||||
|
||||
function decompose(x::Float32)::NTuple{3,Int}
|
||||
isnan(x) && return 0, 0, 0
|
||||
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
|
||||
n = reinterpret(UInt32, x)
|
||||
s = (n & 0x007fffff) % Int32
|
||||
e = (n & 0x7f800000 >> 23) % Int
|
||||
s |= Int32(e != 0) << 23
|
||||
d = ifelse(signbit(x), -1, 1)
|
||||
s, e - 150 + (e == 0), d
|
||||
end
|
||||
|
||||
function decompose(x::Float64)::Tuple{Int64, Int, Int}
|
||||
isnan(x) && return 0, 0, 0
|
||||
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
|
||||
n = reinterpret(UInt64, x)
|
||||
s = (n & 0x000fffffffffffff) % Int64
|
||||
e = (n & 0x7ff0000000000000 >> 52) % Int
|
||||
s |= Int64(e != 0) << 52
|
||||
d = ifelse(signbit(x), -1, 1)
|
||||
s, e - 1075 + (e == 0), d
|
||||
end
|
||||
|
||||
function decompose(x::BigFloat)::Tuple{BigInt, Int, Int}
|
||||
isnan(x) && return 0, 0, 0
|
||||
isinf(x) && return x.sign, 0, 0
|
||||
x == 0 && return 0, 0, x.sign
|
||||
s = BigInt()
|
||||
s.size = cld(x.prec, 8*sizeof(GMP.Limb)) # limbs
|
||||
b = s.size * sizeof(GMP.Limb) # bytes
|
||||
ccall((:__gmpz_realloc2, :libgmp), Void, (Ptr{BigInt}, Culong), &s, 8b) # bits
|
||||
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t), s.d, x.d, b) # bytes
|
||||
s, x.exp - 8b, x.sign
|
||||
end
|
||||
|
||||
## streamlined hashing for smallish rational types ##
|
||||
|
||||
function hash(x::Rational{<:BitInteger64}, h::UInt)
|
||||
num, den = Base.numerator(x), Base.denominator(x)
|
||||
den == 1 && return hash(num, h)
|
||||
den == 0 && return hash(ifelse(num > 0, Inf, -Inf), h)
|
||||
if isodd(den)
|
||||
pow = trailing_zeros(num)
|
||||
num >>= pow
|
||||
else
|
||||
pow = trailing_zeros(den)
|
||||
den >>= pow
|
||||
pow = -pow
|
||||
if den == 1 && abs(num) < 9007199254740992
|
||||
return hash(ldexp(Float64(num),pow))
|
||||
end
|
||||
end
|
||||
h = hash_integer(den, h)
|
||||
h = hash_integer(pow, h)
|
||||
h = hash_integer(num, h)
|
||||
return h
|
||||
end
|
||||
|
||||
## hashing Float16s ##
|
||||
|
||||
hash(x::Float16, h::UInt) = hash(Float64(x), h)
|
||||
|
||||
## hashing strings ##
|
||||
|
||||
const memhash = UInt === UInt64 ? :memhash_seed : :memhash32_seed
|
||||
const memhash_seed = UInt === UInt64 ? 0x71e729fd56419c81 : 0x56419c81
|
||||
|
||||
function hash(s::Union{String,SubString{String}}, h::UInt)
|
||||
h += memhash_seed
|
||||
# note: use pointer(s) here (see #6058).
|
||||
ccall(memhash, UInt, (Ptr{UInt8}, Csize_t, UInt32), pointer(s), sizeof(s), h % UInt32) + h
|
||||
end
|
||||
hash(s::AbstractString, h::UInt) = hash(String(s), h)
|
||||
Reference in New Issue
Block a user