From 19060d93fe8d8f3747c9d315bbed9ddc8a846151 Mon Sep 17 00:00:00 2001 From: Jason Davies Date: Thu, 8 Dec 2011 18:43:12 +0000 Subject: [PATCH] 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. --- bloomfilter.js | 17 +++++++++++--- package.json | 2 +- test/bloomfilter-test.js | 51 +++++----------------------------------- 3 files changed, 21 insertions(+), 49 deletions(-) diff --git a/bloomfilter.js b/bloomfilter.js index b261455..c248d8c 100644 --- a/bloomfilter.js +++ b/bloomfilter.js @@ -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); diff --git a/package.json b/package.json index 09b1fd0..d371b2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bloomfilter", - "version": "0.0.7", + "version": "0.0.8", "description": "Fast bloom filter in JavaScript.", "keywords": [ "bloom filter", diff --git a/test/bloomfilter-test.js b/test/bloomfilter-test.js index e84839c..3a9bc75 100644 --- a/test/bloomfilter-test.js +++ b/test/bloomfilter-test.js @@ -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(""); -}