public long query(HllBuffer buffer) {
        // Compute the inverse of indicator value 'z' and count the number of zeros 'V'.
        double zInverse = 0.0d;
        double v = 0.0d;
        int idx = 0;
        int wordOffset = 0;
        while (wordOffset < numWords) {
            long word = buffer.array[wordOffset];
            int i = 0;
            int shift = 0;
            while (idx < m && i < REGISTERS_PER_WORD) {
                long mIdx = (word >>> shift) & REGISTER_WORD_MASK;
                zInverse += 1.0 / (1 << mIdx);
                if (mIdx == 0) {
                    v += 1.0d;
                }
                shift += REGISTER_SIZE;
                i += 1;
                idx += 1;
            }
            wordOffset += 1;
        }

        // We integrate two steps from the paper:
        // val Z = 1.0d / zInverse
        // val E = alphaM2 * Z
        double e = alphaM2 / zInverse;
        double eBiasCorrected = p < 19 && e < 5.0d * m ? e - estimateBias(e) : e;

        double estimate;
        // Estimate the cardinality.
        if (v > 0) {
            // Use linear counting for small cardinality estimates.
            double h = m * Math.log(m / v);
            // HLL++ is defined only when p < 19, otherwise we need to fallback to HLL.
            // The threshold `2.5 * m` is from the original HLL algorithm.
            if ((p < 19 && h <= THRESHOLDS[p - 4]) || e <= 2.5 * m) {
                estimate = h;
            } else {
                estimate = eBiasCorrected;
            }
        } else {
            estimate = eBiasCorrected;
        }

        // Round to the nearest long value.
        return Math.round(estimate);
    }
@Test
    public void testInputAllNulls() {
        HyperLogLogPlusPlus hll = new HyperLogLogPlusPlus(0.01);
        HllBuffer buffer = createHllBuffer(hll);
        long estimate = hll.query(buffer);
        assertThat(estimate).isEqualTo(0);
    }