Skip to content

Commit f791029

Browse files
move generic rational hashing definitions into hashing2.jl
1 parent 316eeda commit f791029

File tree

2 files changed

+112
-118
lines changed

2 files changed

+112
-118
lines changed

base/hashing.jl

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -27,130 +27,18 @@ function hash_uint(n::Uint32)
2727
return a
2828
end
2929

30-
## efficient value-based hashing of integers ##
31-
32-
function hash_integer(n::Integer, h::Uint)
33-
h = hash_uint(uint(n & typemax(Uint)) $ h) $ h
34-
n = ifelse(n < 0, oftype(n,-n), n)
35-
n >>>= sizeof(Uint) << 3
36-
while n != 0
37-
h = hash_uint(uint(n & typemax(Uint)) $ h) $ h
38-
n >>>= sizeof(Uint) << 3
39-
end
40-
return h
41-
end
42-
43-
## hashing rational values ##
44-
45-
#=
46-
`decompose(x)`: non-canonical decomposition of rational values as `num*2^pow/den`.
47-
48-
The decompose function is the point where rational-valued numeric types that support
49-
hashing hook into the hashing protocol. `decompose(x)` should return three integer
50-
values `num, pow, den`, such that the value of `x` is mathematically equal to
51-
52-
num*2^pow/den
53-
54-
The decomposition need not be canonical in the sense that it just needs to be *some*
55-
way to express `x` in this form, not any particular way – with the restriction that
56-
`num` and `den` may not share any odd common factors. They may, however, have powers
57-
of two in common – the generic hashing code will normalize those as necessary.
58-
59-
Special values:
60-
61-
- `x` is zero: `num` should be zero and `den` should have the same sign as `x`
62-
- `x` is infinite: `den` should be zero and `num` should have the same sign as `x`
63-
- `x` is not a number: `num` and `den` should both be zero
64-
=#
65-
66-
decompose(x::Integer) = x, 0, 1
67-
decompose(x::Rational) = num(x), 0, den(x)
68-
69-
function decompose(x::Float32)
70-
isnan(x) && return 0, 0, 0
71-
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
72-
n = reinterpret(Int32, x)
73-
s = int32(n & 0x007fffff)
74-
e = int32(n & 0x7f800000 >> 23)
75-
s |= int32(e != 0) << 23
76-
d = ifelse(signbit(n) == 1, -1, 1)
77-
int(s), int(e - 150 + (e == 0)), d
78-
end
79-
80-
function decompose(x::Float64)
81-
isnan(x) && return 0, 0, 0
82-
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
83-
n = reinterpret(Int64, x)
84-
s = int64(n & 0x000fffffffffffff)
85-
e = int64(n & 0x7ff0000000000000 >> 52)
86-
s |= int64(e != 0) << 52
87-
d = ifelse(signbit(n) == 1, -1, 1)
88-
int(s), int(e - 1075 + (e == 0)), d
89-
end
90-
91-
# hashing methods for rational-valued types
30+
## hashing small, built-in numeric types ##
9231

9332
hx(a::Uint64, b::Float64, h::Uint) = hash_uint((3a + reinterpret(Uint64,b)) - h)
9433

9534
hash(x::Uint64, h::Uint) = hx(x, float64(x), h)
9635
hash(x::Int64, h::Uint) = hx(reinterpret(Uint64,x), float64(x), h)
97-
hash(x::Float64, h::Uint) = hx(box(Uint64,fptosi(unbox(Float64,x))), ifelse(x==x,x,NaN), h)
36+
hash(x::Float64, h::Uint) = hx(box(Uint64,fptosi(unbox(Float64,x))), ifelse(isnan(x), NaN, x), h)
9837

9938
hash(x::Union(Int8,Uint8,Int16,Uint16,Int32,Uint32), h::Uint) = hash(int64(x), h)
10039
hash(x::Float32, h::Uint) = hash(float64(x), h)
10140

102-
function hash(x::Real, h::Uint)
103-
# decompose x as num*2^pow/den
104-
num, pow, den = decompose(x)::(Integer,Integer,Integer)
105-
106-
# handle special values
107-
num == 0 && den == 0 && return hash(NaN, h)
108-
if num == 0
109-
den > 0 && return hash(+0.0, h)
110-
den < 0 && return hash(-0.0, h)
111-
end
112-
if den == 0
113-
num > 0 && return hash(+Inf, h)
114-
num < 0 && return hash(-Inf, h)
115-
end
116-
117-
# normalize decomposition
118-
if den < 0
119-
num = -num
120-
den = -den
121-
end
122-
z = trailing_zeros(num)
123-
if z != 0
124-
num >>= z
125-
pow += z
126-
end
127-
z = trailing_zeros(den)
128-
if z != 0
129-
den >>= z
130-
pow -= z
131-
end
132-
133-
# handle values representable as Int64, Uint64, Float64
134-
if den == 1
135-
left = ndigits0z(num,2) + pow
136-
right = trailing_zeros(num) + pow
137-
if -1074 <= right
138-
if 0 <= right && left <= 64
139-
left <= 63 && return hash(int64(num) << int(pow), h)
140-
signbit(num) == signbit(den) && return hash(uint64(num) << int(pow), h)
141-
end
142-
left <= 1024 && left - right <= 53 && return hash(float64(num) * 2.0^pow, h)
143-
end
144-
end
145-
146-
# handle "generic" real values
147-
h = hash_integer(den, h)
148-
h = hash_integer(pow, h)
149-
h = hash_integer(num, h)
150-
return h
151-
end
152-
153-
## hashing complex values ##
41+
## hashing complex numbers ##
15442

15543
const h_imag = 0x32a7a07f3e7cd1f9
15644
const hash_0_imag = hash(0, h_imag)
@@ -166,7 +54,7 @@ end
16654
hash(x::Bool, h::Uint) = hash(int(x), h + 0x4cd135a1755139a5)
16755
hash(x::Char, h::Uint) = hash(int(x), h + 0x10f989ff0f886f11)
16856

169-
## expression hashing ##
57+
## symbol & expression hashing ##
17058

17159
hash(x::Symbol, h::Uint) = hash(object_id(x), h)
17260
hash(x::Expr, h::Uint) = hash(x.args, hash(x.head, h + 0x83c7900696d26dc6))

base/hashing2.jl

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
## hashing BigInts, BigFloats, and Float16s ##
1+
## efficient value-based hashing of integers ##
2+
3+
function hash_integer(n::Integer, h::Uint)
4+
h = hash_uint(uint(n & typemax(Uint)) $ h) $ h
5+
n = ifelse(n < 0, oftype(n,-n), n)
6+
n >>>= sizeof(Uint) << 3
7+
while n != 0
8+
h = hash_uint(uint(n & typemax(Uint)) $ h) $ h
9+
n >>>= sizeof(Uint) << 3
10+
end
11+
return h
12+
end
213

314
function hash_integer(n::BigInt, h::Uint)
415
s = n.size
@@ -12,6 +23,99 @@ function hash_integer(n::BigInt, h::Uint)
1223
return h
1324
end
1425

26+
## generic hashing for rational values ##
27+
28+
function hash(x::Real, h::Uint)
29+
# decompose x as num*2^pow/den
30+
num, pow, den = decompose(x)::(Integer,Integer,Integer)
31+
32+
# handle special values
33+
num == 0 && den == 0 && return hash(NaN, h)
34+
num == 0 && return hash(ifelse(den > 0, 0.0, -0.0), h)
35+
den == 0 && return hash(ifelse(num > 0, Inf, -Inf), h)
36+
37+
# normalize decomposition
38+
if den < 0
39+
num = -num
40+
den = -den
41+
end
42+
z = trailing_zeros(num)
43+
if z != 0
44+
num >>= z
45+
pow += z
46+
end
47+
z = trailing_zeros(den)
48+
if z != 0
49+
den >>= z
50+
pow -= z
51+
end
52+
53+
# handle values representable as Int64, Uint64, Float64
54+
if den == 1
55+
left = ndigits0z(num,2) + pow
56+
right = trailing_zeros(num) + pow
57+
if -1074 <= right
58+
if 0 <= right && left <= 64
59+
left <= 63 && return hash(int64(num) << int(pow), h)
60+
signbit(num) == signbit(den) && return hash(uint64(num) << int(pow), h)
61+
end # typemin(Int64) handled by Float64 case
62+
left <= 1024 && left - right <= 53 && return hash(float64(num) * 2.0^pow, h)
63+
end
64+
end
65+
66+
# handle generic rational values
67+
h = hash_integer(den, h)
68+
h = hash_integer(pow, h)
69+
h = hash_integer(num, h)
70+
return h
71+
end
72+
73+
#=
74+
`decompose(x)`: non-canonical decomposition of rational values as `num*2^pow/den`.
75+
76+
The decompose function is the point where rational-valued numeric types that support
77+
hashing hook into the hashing protocol. `decompose(x)` should return three integer
78+
values `num, pow, den`, such that the value of `x` is mathematically equal to
79+
80+
num*2^pow/den
81+
82+
The decomposition need not be canonical in the sense that it just needs to be *some*
83+
way to express `x` in this form, not any particular way – with the restriction that
84+
`num` and `den` may not share any odd common factors. They may, however, have powers
85+
of two in common – the generic hashing code will normalize those as necessary.
86+
87+
Special values:
88+
89+
- `x` is zero: `num` should be zero and `den` should have the same sign as `x`
90+
- `x` is infinite: `den` should be zero and `num` should have the same sign as `x`
91+
- `x` is not a number: `num` and `den` should both be zero
92+
=#
93+
94+
decompose(x::Integer) = x, 0, 1
95+
decompose(x::Rational) = num(x), 0, den(x)
96+
97+
function decompose(x::Float32)
98+
isnan(x) && return 0, 0, 0
99+
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
100+
n = reinterpret(Int32, x)
101+
s = int32(n & 0x007fffff)
102+
e = int32(n & 0x7f800000 >> 23)
103+
s |= int32(e != 0) << 23
104+
d = ifelse(signbit(n) == 1, -1, 1)
105+
int(s), int(e - 150 + (e == 0)), d
106+
end
107+
108+
function decompose(x::Float64)
109+
isnan(x) && return 0, 0, 0
110+
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
111+
n = reinterpret(Int64, x)
112+
s = int64(n & 0x000fffffffffffff)
113+
e = int64(n & 0x7ff0000000000000 >> 52)
114+
s |= int64(e != 0) << 52
115+
d = ifelse(signbit(n) == 1, -1, 1)
116+
int(s), int(e - 1075 + (e == 0)), d
117+
end
118+
15119
function decompose(x::BigFloat)
16120
isnan(x) && return big(0), 0, 0
17121
isinf(x) && return big(x.sign), 0, 0
@@ -23,6 +127,8 @@ function decompose(x::BigFloat)
23127
s, int(x.exp - x.prec), int(x.sign)
24128
end
25129

130+
## hashing Float16s ##
131+
26132
hash(x::Float16, h::Uint) = hash(float64(x), h)
27133

28134
## hashing strings ##
@@ -53,6 +159,6 @@ hash(a::AbstractArray{Bool}, h::Uint) = hash(bitpack(a), h)
53159
hash{T<:Range}(r::T, h::Uint) =
54160
hash(first(r), hash(step(r), hash(last(r), h + object_id(eltype(T)))))
55161

56-
## hashing general objects and expressions ##
162+
## hashing general objects ##
57163

58164
hash(x::ANY, h::Uint) = hash(object_id(x), h)

0 commit comments

Comments
 (0)