stats/src/main/java/io/airlift/stats/QuantileDigest.java
public List<Bucket> getHistogram(List<Long> bucketUpperBounds, MiddleFunction middleFunction)
    {
        checkArgument(Ordering.natural().isOrdered(bucketUpperBounds), "buckets must be sorted in increasing order");

        ImmutableList.Builder<Bucket> builder = ImmutableList.builder();
        PeekingIterator<Long> iterator = Iterators.peekingIterator(bucketUpperBounds.iterator());

        HistogramBuilderStateHolder holder = new HistogramBuilderStateHolder();

        double normalizationFactor = weight(TimeUnit.NANOSECONDS.toSeconds(ticker.read()));

        postOrderTraversal(root, node -> {
            while (iterator.hasNext() && iterator.peek() <= upperBound(node)) {
                double bucketCount = holder.sum - holder.lastSum;

                Bucket bucket = new Bucket(bucketCount / normalizationFactor, holder.bucketWeightedSum / bucketCount);

                builder.add(bucket);
                holder.lastSum = holder.sum;
                holder.bucketWeightedSum = 0;
                iterator.next();
            }

            holder.bucketWeightedSum += middleFunction.middle(lowerBound(node), upperBound(node)) * counts[node];
            holder.sum += counts[node];
            return iterator.hasNext();
        });

        while (iterator.hasNext()) {
            double bucketCount = holder.sum - holder.lastSum;
            Bucket bucket = new Bucket(bucketCount / normalizationFactor, holder.bucketWeightedSum / bucketCount);

            builder.add(bucket);

            iterator.next();
        }

        return builder.build();
    }
public List<Bucket> getHistogram(List<Long> bucketUpperBounds, MiddleFunction middleFunction)
    {
        checkArgument(Ordering.natural().isOrdered(bucketUpperBounds), "buckets must be sorted in increasing order");

        ImmutableList.Builder<Bucket> builder = ImmutableList.builder();
        PeekingIterator<Long> iterator = Iterators.peekingIterator(bucketUpperBounds.iterator());

        HistogramBuilderStateHolder holder = new HistogramBuilderStateHolder();

        double normalizationFactor = weight(TimeUnit.NANOSECONDS.toSeconds(ticker.read()));

        postOrderTraversal(root, node -> {
            while (iterator.hasNext() && iterator.peek() <= upperBound(node)) {
                double bucketCount = holder.sum - holder.lastSum;

                Bucket bucket = new Bucket(bucketCount / normalizationFactor, holder.bucketWeightedSum / bucketCount);

                builder.add(bucket);
                holder.lastSum = holder.sum;
                holder.bucketWeightedSum = 0;
                iterator.next();
            }

            holder.bucketWeightedSum += middleFunction.middle(lowerBound(node), upperBound(node)) * counts[node];
            holder.sum += counts[node];
            return iterator.hasNext();
        });

        while (iterator.hasNext()) {
            double bucketCount = holder.sum - holder.lastSum;
            Bucket bucket = new Bucket(bucketCount / normalizationFactor, holder.bucketWeightedSum / bucketCount);

            builder.add(bucket);

            iterator.next();
        }

        return builder.build();
    }
is calculated.