@Override
    public ICardinality merge(ICardinality... estimators) throws LogLogMergeException {
        if (estimators == null) {
            return new LogLog(M);
        }

        byte[] mergedBytes = Arrays.copyOf(this.M, this.M.length);
        for (ICardinality estimator : estimators) {
            if (!(this.getClass().isInstance(estimator))) {
                throw new LogLogMergeException("Cannot merge estimators of different class");
            }
            if (estimator.sizeof() != this.sizeof()) {
                throw new LogLogMergeException("Cannot merge estimators of different sizes");
            }
            LogLog ll = (LogLog) estimator;
            for (int i = 0; i < mergedBytes.length; ++i) {
                mergedBytes[i] = (byte) Math.max(mergedBytes[i], ll.M[i]);
            }
        }

        return new LogLog(mergedBytes);
    }
@Test
    public void testMerge() throws CardinalityMergeException {
        int numToMerge = 5;
        int bits = 16;
        int cardinality = 1000000;

        LogLog[] loglogs = new LogLog[numToMerge];
        LogLog baseline = new LogLog(bits);
        for (int i = 0; i < numToMerge; i++) {
            loglogs[i] = new LogLog(bits);
            for (int j = 0; j < cardinality; j++) {
                double val = Math.random();
                loglogs[i].offer(val);
                baseline.offer(val);
            }
        }


        LogLog hll = loglogs[0];
        loglogs = Arrays.asList(loglogs).subList(1, loglogs.length).toArray(new LogLog[0]);
        long mergedEstimate = hll.merge(loglogs).cardinality();
        long baselineEstimate = baseline.cardinality();

        System.out.println("Baseline estimate: " + baselineEstimate);

        assertEquals(mergedEstimate, baselineEstimate);
    }