-
Notifications
You must be signed in to change notification settings - Fork 0
/
cbf.go
67 lines (57 loc) · 1.33 KB
/
cbf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package bloomfilter
import (
"hash"
"hash/fnv"
"math"
)
type CountingBloomFilter struct {
m int
k int
h hash.Hash32
bits []int
}
func NewCountingBloomFilter(numbers uint32, falsePositiveProbability float64) *CountingBloomFilter {
cbf := &CountingBloomFilter{h: fnv.New32()}
cbf.estimate(numbers, falsePositiveProbability)
cbf.bits = make([]int, cbf.m)
return cbf
}
func (cbf *CountingBloomFilter) estimate(n uint32, p float64) {
// m = -1 * (n * ln(P)) / (ln2)^2
cbf.m = int(-1 * (float64(n) * math.Log(p)) / math.Pow(math.Log(2), 2))
// k = -1 * (lnP) / (ln2)
// k = m / n * ln2
cbf.k = int(float64(cbf.m) / float64(n) * math.Log(2))
}
func (cbf *CountingBloomFilter) hash(idx int, element []byte) int {
cbf.h.Reset()
cbf.h.Write(element)
d := int(cbf.h.Sum32())
return (d + idx) % cbf.m
}
func (cbf *CountingBloomFilter) Add(element []byte) {
for i := 0; i < cbf.k; i++ {
idx := cbf.hash(i, element)
cbf.bits[idx]++
}
}
func (cbf *CountingBloomFilter) Exist(element []byte) bool {
for i := 0; i < cbf.k; i++ {
idx := cbf.hash(i, element)
if cbf.bits[idx] == 0 {
return false
}
}
return true
}
func (cbf *CountingBloomFilter) Remove(element []byte) {
if !cbf.Exist(element) {
return
}
for i := 0; i < cbf.k; i++ {
idx := cbf.hash(i, element)
if cbf.bits[idx] > 0 {
cbf.bits[idx]--
}
}
}