public static BloomSpecification computeBucketsAndK(double maxFalsePosProb){
        // Handle the trivial cases
        if(maxFalsePosProb >= probs[minBuckets][minK]) {
            return new BloomSpecification(2, optKPerBuckets[2]);
        }
        if(maxFalsePosProb < probs[maxBuckets][maxK]) {
            return new BloomSpecification(maxK, maxBuckets);
        }

        // First find the minimal required number of buckets:
        int bucketsPerElement = 2;
        int K = optKPerBuckets[2];
        while(probs[bucketsPerElement][K] > maxFalsePosProb){
            bucketsPerElement++;
            K = optKPerBuckets[bucketsPerElement];
        }
        // Now that the number of buckets is sufficient, see if we can relax K
        // without losing too much precision.
        while(probs[bucketsPerElement][K - 1] <= maxFalsePosProb){
            K--;
        }

        return new BloomSpecification(K, bucketsPerElement);
    }