The finale runs the stream through HyperLogLog for the distinct count, then stands back to see all three sketches answering their questions about one stream at once. The library is complete.
Estimate the stream's distinct count with HyperLogLog and confirm all three sketches agree with the truth.
The last sketch answers cardinality. Feeding the stream to a HyperLogLog fills just four registers - one per distinct word - and leaves twelve empty. That sparse state triggers the small-range correction, and linear counting reads the twelve empties as about 4.60 distinct items, a close call on the true 4 even at this tiny 16-register size.
Step back and the whole library is in view. One stream, three questions, three space-efficient answers: the Bloom filter never forgets a member and only ever risks a false positive; the Count-Min sketch estimates every frequency without ever under-counting; and HyperLogLog counts the distinct items from a handful of bytes. Every bit, counter, and register along the way was pinned to an exact value, because the hash functions were specified rather than borrowed - so the library you built is reproducible in any language. From a bit array and a pair of hashes, you have built the honest core of the probabilistic data structures that power real databases, caches, and stream processors. That is the whole toolkit, and it is yours.
h := NewHLL(4)for _, tok := range stream { h.Add([]byte(tok)) }// registers == [0,0,0,0,0,2,0,0,0,0,0,0,1,1,0,2], 12 empty// Estimate() ~= 4.60 (linear counting), true distinct == 4