When doing a union between two compatible HyperLogLog objects, you can just take the maximum bucket to do a lossless union that doesn't introduce any new error:
Union.Bucket[i] = Max(A.Bucket[i], B.Bucket[i])
When doing an intersection though, you have to use the inclusion-exclusion principle:
IntersectionCountEstimate = A.CountEstimate() + B.CountEstimate() - Union.CountEstimate()
Why is it that using the minimum bucket value doesn't work as an effective intersection?
Intersection.Bucket[i] = Min(A.Bucket[i], B.Bucket[i])