1
0
forked from Mirror/wren

Merge pull request #693 from wren-lang/faster-bit-hash

Fix horrendously bad bit hashing function.
This commit is contained in:
Bob Nystrom
2019-07-27 21:00:02 -07:00
committed by GitHub
7 changed files with 29 additions and 37 deletions

View File

@ -356,24 +356,18 @@ ObjMap* wrenNewMap(WrenVM* vm)
return map; return map;
} }
static inline uint32_t hashBits(DoubleBits bits) static inline uint32_t hashBits(uint64_t hash)
{ {
uint32_t result = bits.bits32[0] ^ bits.bits32[1]; // From v8's ComputeLongHash() which in turn cites:
// Thomas Wang, Integer Hash Functions.
// Slosh the bits around some. Due to the way doubles are represented, small // http://www.concentric.net/~Ttwang/tech/inthash.htm
// integers will have most of low bits of the double respresentation set to hash = ~hash + (hash << 18); // hash = (hash << 18) - hash - 1;
// zero. For example, the above result for 5 is 43d00600. hash = hash ^ (hash >> 31);
// hash = hash * 21; // hash = (hash + (hash << 2)) + (hash << 4);
// We map that to an entry index by masking off the high bits which means hash = hash ^ (hash >> 11);
// most small integers would all end up in entry zero. That's bad. To avoid hash = hash + (hash << 6);
// that, push a bunch of the high bits lower down so they affect the lower hash = hash ^ (hash >> 22);
// bits too. return (uint32_t)(hash & 0x3fffffff);
//
// The specific mixing function here was pulled from Java's HashMap
// implementation.
result ^= (result >> 20) ^ (result >> 12);
result ^= (result >> 7) ^ (result >> 4);
return result;
} }
// Generates a hash code for [num]. // Generates a hash code for [num].
@ -382,7 +376,7 @@ static inline uint32_t hashNumber(double num)
// Hash the raw bits of the value. // Hash the raw bits of the value.
DoubleBits bits; DoubleBits bits;
bits.num = num; bits.num = num;
return hashBits(bits); return hashBits(bits.bits64);
} }
// Generates a hash code for [object]. // Generates a hash code for [object].
@ -429,9 +423,7 @@ static uint32_t hashValue(Value value)
if (IS_OBJ(value)) return hashObject(AS_OBJ(value)); if (IS_OBJ(value)) return hashObject(AS_OBJ(value));
// Hash the raw bits of the unboxed value. // Hash the raw bits of the unboxed value.
DoubleBits bits; return hashBits(value);
bits.bits64 = value;
return hashBits(bits);
#else #else
switch (value.type) switch (value.type)
{ {

View File

@ -6,17 +6,17 @@ main() {
var map = {}; var map = {};
for (var i = 1; i <= 1000000; i++) { for (var i = 1; i <= 2000000; i++) {
map[i] = i; map[i] = i;
} }
var sum = 0; var sum = 0;
for (var i = 1; i <= 1000000; i++) { for (var i = 1; i <= 2000000; i++) {
sum += map[i]; sum += map[i];
} }
print(sum); print(sum);
for (var i = 1; i <= 1000000; i++) { for (var i = 1; i <= 2000000; i++) {
map.remove(i); map.remove(i);
} }

View File

@ -2,17 +2,17 @@ local start = os.clock()
local map = {} local map = {}
for i = 1, 1000000 do for i = 1, 2000000 do
map[i] = i map[i] = i
end end
local sum = 0 local sum = 0
for i = 1, 1000000 do for i = 1, 2000000 do
sum = sum + map[i] sum = sum + map[i]
end end
io.write(string.format("%d\n", sum)) io.write(string.format("%d\n", sum))
for i = 1, 1000000 do for i = 1, 2000000 do
map[i] = nil map[i] = nil
end end

View File

@ -6,15 +6,15 @@ start = time.clock()
map = {} map = {}
for i in range(1, 1000001): for i in range(1, 2000001):
map[i] = i map[i] = i
sum = 0 sum = 0
for i in range(1, 1000001): for i in range(1, 2000001):
sum = sum + map[i] sum = sum + map[i]
print(sum) print(sum)
for i in range(1, 1000001): for i in range(1, 2000001):
del map[i] del map[i]
print("elapsed: " + str(time.clock() - start)) print("elapsed: " + str(time.clock() - start))

View File

@ -2,17 +2,17 @@ start = Time.now
map = Hash.new map = Hash.new
for i in (1..1000000) for i in (1..2000000)
map[i] = i map[i] = i
end end
sum = 0 sum = 0
for i in (1..1000000) for i in (1..2000000)
sum = sum + map[i] sum = sum + map[i]
end end
puts sum puts sum
for i in (1..1000000) for i in (1..2000000)
map.delete(i) map.delete(i)
end end

View File

@ -2,17 +2,17 @@ var start = System.clock
var map = {} var map = {}
for (i in 1..1000000) { for (i in 1..2000000) {
map[i] = i map[i] = i
} }
var sum = 0 var sum = 0
for (i in 1..1000000) { for (i in 1..2000000) {
sum = sum + map[i] sum = sum + map[i]
} }
System.print(sum) System.print(sum)
for (i in 1..1000000) { for (i in 1..2000000) {
map.remove(i) map.remove(i)
} }

View File

@ -86,7 +86,7 @@ BENCHMARK("for", r"""499999500000""")
BENCHMARK("method_call", r"""true BENCHMARK("method_call", r"""true
false""") false""")
BENCHMARK("map_numeric", r"""500000500000""") BENCHMARK("map_numeric", r"""2000001000000""")
BENCHMARK("map_string", r"""12799920000""") BENCHMARK("map_string", r"""12799920000""")