func (p *PartitionedBloomFilter) Add(data []byte) Filter {
	lower, upper := hashKernel(data, p.hash)
	for i := uint(0); i < p.k; i++ {
		p.partitions[i].Set((uint(lower)+uint(upper)*i)%p.s, 1)
	}
	p.count++
	return p
}
Add will add the data to the Bloom filter. It returns the filter to allow
for chaining.
package boom
import (
	"bytes"
	"encoding/binary"
	"hash"
	"hash/fnv"
	"io"
	"math"
)
type PartitionedBloomFilter struct {
	partitions []*Buckets   
	hash       hash.Hash64  
	m          uint         
	k          uint         
	s          uint         
	count      uint         
}
func NewPartitionedBloomFilter(n uint, fpRate float64) *PartitionedBloomFilter {
	var (
		m          = OptimalM(n, fpRate)
		k          = OptimalK(fpRate)
		partitions = make([]*Buckets, k)
		s          = uint(math.Ceil(float64(m) / float64(k)))
	)
	for i := uint(0); i < k; i++ {
		partitions[i] = NewBuckets(s, 1)
	}
	return &PartitionedBloomFilter{
		partitions: partitions,
		hash:       fnv.New64(),
		m:          m,
		k:          k,
		s:          s,
	}
}
func (p *PartitionedBloomFilter) Capacity() uint {
	return p.m
}
func (p *PartitionedBloomFilter) K() uint {
	return p.k
}
func (p *PartitionedBloomFilter) Count() uint {
	return p.count
}
func (p *PartitionedBloomFilter) EstimatedFillRatio() float64 {
	return 1 - math.Exp(-float64(p.count)/float64(p.s))
}
func (p *PartitionedBloomFilter) FillRatio() float64 {
	t := float64(0)
	for i := uint(0); i < p.k; i++ {
		sum := uint32(0)
		for j := uint(0); j < p.partitions[i].Count(); j++ {
			sum += p.partitions[i].Get(j)
		}
		t += (float64(sum) / float64(p.s))
	}
	return t / float64(p.k)
}
func (p *PartitionedBloomFilter) Test(data []byte) bool {
	lower, upper := hashKernel(data, p.hash)
	for i := uint(0); i < p.k; i++ {
		if p.partitions[i].Get((uint(lower)+uint(upper)*i)%p.s) == 0 {
			return false
		}
	}
	return true
}