code: static final double hllLowerBound(final AbstractHllArray absHllArr, final int numStdDev) {
      final int lgConfigK = absHllArr.lgConfigK;
      final int configK = 1 << lgConfigK;
      final double numNonZeros =
          (absHllArr.getCurMin() == 0) ? configK - absHllArr.getNumAtCurMin() : configK;
      final double estimate;
      final double rseFactor;
      final boolean oooFlag = absHllArr.isOutOfOrderFlag();
      if (oooFlag) {
        estimate = absHllArr.getCompositeEstimate();
        rseFactor = HLL_NON_HIP_RSE_FACTOR;
      } else {
        estimate = absHllArr.getHipAccum();
        rseFactor = HLL_HIP_RSE_FACTOR;
      }
      final double relErr = (lgConfigK > 12)
          ? (numStdDev * rseFactor) / Math.sqrt(configK)
          : RelativeErrorTables.getRelErr(false, oooFlag, lgConfigK, numStdDev);
      return Math.max(estimate / (1.0 + relErr), numNonZeros);
    }
docs: /*
  The upper and lower bounds are not symmetric and thus are treated slightly differently.
  For the lower bound, when the unique count is <= k, LB >= numNonZeros, where
  numNonZeros = k - numAtCurMin AND curMin == 0.
  
  For HLL6 and HLL8, curMin is always 0 and numAtCurMin is initialized to k and is decremented
  down for each valid update until it reaches 0, where it stays. Thus, for these two
  isomorphs, when numAtCurMin = 0, means the true curMin is > 0 and the unique count must be
  greater than k.
  
  HLL4 always maintains both curMin and numAtCurMin dynamically. Nonetheless, the rules for
  the very small values <= k where curMin = 0 still apply.