More mixing added to FNV-1a.

Lack of sufficient mixing was causing "wtf" to hash poorly in the second
hash function, and only map to one location instead of ten.
This commit is contained in:
Jason Davies 2011-12-08 18:43:12 +00:00
parent 7d362348c6
commit 19060d93fe
3 changed files with 21 additions and 49 deletions

View File

@ -33,10 +33,10 @@
a = fnv_1a(v),
b = fnv_1a_b(a),
i = -1,
x;
x = a % m;
while (++i < k) {
x = (a + b * i) % m;
r[i] = x < 0 ? x + m : x;
r[i] = x < 0 ? (x + m) : x;
x = (x + b) % m;
}
return r;
};
@ -90,12 +90,23 @@
a ^= c & 0xff;
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
}
// From http://home.comcast.net/~bretm/hash/6.html
a += a << 13;
a ^= a >> 7;
a += a << 3;
a ^= a >> 17;
a += a << 5;
return a & 0xffffffff;
}
// One additional iteration of FNV, given a hash.
function fnv_1a_b(a) {
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
a += a << 13;
a ^= a >> 7;
a += a << 3;
a ^= a >> 17;
a += a << 5;
return a & 0xffffffff;
}
})(typeof exports !== "undefined" ? exports : this);

View File

@ -1,6 +1,6 @@
{
"name": "bloomfilter",
"version": "0.0.7",
"version": "0.0.8",
"description": "Fast bloom filter in JavaScript.",
"keywords": [
"bloom filter",

View File

@ -1,6 +1,7 @@
var bf = require("../bloomfilter"),
BloomFilter = bf.BloomFilter,
fnv_1a = bf.fnv_1a;
fnv_1a = bf.fnv_1a,
fnv_1a_b = bf.fnv_1a_b;
var vows = require("vows"),
assert = require("assert");
@ -36,52 +37,12 @@ suite.addBatch({
assert.equal(f.test(n1), true);
assert.equal(f.test(n2), false);
assert.equal(f.test(n3), false);
}
},
"fnv": {
"basic": function() {
// Test vectors from http://isthe.com/chongo/tech/comp/fnv/
assert.equal(fnv_1a(""), 0x811c9dc5 & 0xffffffff);
assert.equal(fnv_1a("a"), 0xe40c292c & 0xffffffff);
assert.equal(fnv_1a("b"), 0xe70c2de5 & 0xffffffff);
assert.equal(fnv_1a("c"), 0xe60c2c52 & 0xffffffff);
assert.equal(fnv_1a("d"), 0xe10c2473 & 0xffffffff);
assert.equal(fnv_1a("e"), 0xe00c22e0 & 0xffffffff);
assert.equal(fnv_1a("f"), 0xe30c2799 & 0xffffffff);
assert.equal(fnv_1a("fo"), 0x6222e842 & 0xffffffff);
assert.equal(fnv_1a("foo"), 0xa9f37ed7 & 0xffffffff);
assert.equal(fnv_1a("foob"), 0x3f5076ef & 0xffffffff);
assert.equal(fnv_1a("fooba"), 0x39aaa18a & 0xffffffff);
assert.equal(fnv_1a("foobar"), 0xbf9cf968 & 0xffffffff);
assert.equal(fnv_1a("ch"), 0x5f299f4e & 0xffffffff);
assert.equal(fnv_1a("cho"), 0xef8580f3 & 0xffffffff);
assert.equal(fnv_1a("chon"), 0xac297727 & 0xffffffff);
assert.equal(fnv_1a("chong"), 0x4546b9c0 & 0xffffffff);
assert.equal(fnv_1a("chongo"), 0xbd564e7d & 0xffffffff);
assert.equal(fnv_1a("chongo "), 0x6bdd5c67 & 0xffffffff);
assert.equal(fnv_1a("chongo w"), 0xdd77ed30 & 0xffffffff);
assert.equal(fnv_1a("chongo wa"), 0xf4ca9683 & 0xffffffff);
assert.equal(fnv_1a("chongo was"), 0x4aeb9bd0 & 0xffffffff);
assert.equal(fnv_1a("chongo was "), 0xe0e67ad0 & 0xffffffff);
assert.equal(fnv_1a("chongo was h"), 0xc2d32fa8 & 0xffffffff);
assert.equal(fnv_1a("chongo was he"), 0x7f743fb7 & 0xffffffff);
assert.equal(fnv_1a("chongo was her"), 0x6900631f & 0xffffffff);
assert.equal(fnv_1a("chongo was here"), 0xc59c990e & 0xffffffff);
assert.equal(fnv_1a("chongo was here!"), 0x448524fd & 0xffffffff);
assert.equal(fnv_1a("chongo was here!\n"), 0xd49930d5 & 0xffffffff);
assert.equal(fnv_1a(repeat(500, "\x00")), 0xfa823dd5 & 0xffffffff);
assert.equal(fnv_1a(repeat(500, "\x07")), 0x21a27271 & 0xffffffff);
assert.equal(fnv_1a(repeat(500, "~")), 0x83c5c6d5 & 0xffffffff);
assert.equal(fnv_1a(repeat(500, "\x7f")), 0x813b0881 & 0xffffffff);
},
"wtf": function() {
var f = new BloomFilter(20, 10);
assert.equal(f.locations("wtf").length, 10);
}
}
});
suite.export(module);
function repeat(n, d) {
var r = [],
i = -1;
while (++i < n) r[i] = d;
return r.join("");
}