AdaptiveCounting extends LogLog { @Override public IRichCardinality merge(IRichCardinality... estimators) throws LogLogMergeException { LogLog res = (LogLog) super.merge(estimators); return new AdaptiveCounting(res.M); } AdaptiveCounting(int k);  AdaptiveCounting(byte[] M); @Override boolean offer(Object o); @Override long cardinality(); @Override IRichCardinality merge(IRichCardinality... estimators); static AdaptiveCounting mergeEstimators(LogLog... estimators);  }
@Test public void testMerge() throws CardinalityMergeException { int numToMerge = 10; int cardinality = 10000; AdaptiveCounting[] lcs = new AdaptiveCounting[numToMerge]; AdaptiveCounting baseline = new AdaptiveCounting(16); for (int i = 0; i < numToMerge; i++) { lcs[i] = new AdaptiveCounting(16); for (int j = 0; j < cardinality; j++) { double val = Math.random(); lcs[i].offer(val); baseline.offer(val); } } int expectedCardinality = numToMerge * cardinality; long mergedEstimate = AdaptiveCounting.mergeEstimators(lcs).cardinality(); double error = Math.abs(mergedEstimate - expectedCardinality) / (double) expectedCardinality; assertEquals(0.01, error, 0.01); AdaptiveCounting lc = lcs[0]; lcs = Arrays.asList(lcs).subList(1, lcs.length).toArray(new AdaptiveCounting[0]); mergedEstimate = lc.merge(lcs).cardinality(); error = Math.abs(mergedEstimate - expectedCardinality) / (double) expectedCardinality; assertEquals(0.01, error, 0.01); assertEquals(baseline.cardinality(), mergedEstimate); }