001package org.javasimon.callback.quantiles;
002
003/**
004 * Exponentially organized {@link Buckets}.
005 *
006 * @author Alexej Vlasov
007 */
008public class ExponentialBuckets extends Buckets {
009        /**
010         * Power between buckets.
011         */
012        private final double power;
013
014        /**
015         * Logarithm of the lower bound.
016         */
017        private final double logMin;
018
019        /**
020         * Constructor.
021         *
022         * @param min Duration min (lower bound of all buckets)
023         * @param max Duration max (upper bound of all buckets)
024         * @param bucketNb Number of buckets between min and max
025         */
026        public ExponentialBuckets(long min, long max, int bucketNb) {
027                super(min, max, bucketNb);
028                logMin = Math.log(this.min);
029                power = (Math.log(this.max) - logMin) / bucketNb;
030                long currentMin, currentMax = this.min;
031                for (int i = 1; i <= bucketNb; i++) {
032                        currentMin = currentMax;
033                        currentMax = Math.round(Math.exp(power * i)) * this.min;
034                        buckets[i] = new Bucket(currentMin, currentMax);
035                }
036        }
037
038        /**
039         * {@inheritDoc}
040         * <p/>
041         * Override the base method making it faster thanks to exponential regression.
042         */
043        protected Bucket getBucketForValue(long value) {
044                Bucket bucket;
045                if (value >= max) {
046                        bucket = buckets[bucketNb + 1];
047                } else {
048                        if (value < min) {
049                                bucket = buckets[0];
050                        } else {
051                                int idx = (int) Math.floor((Math.log(value) - logMin) / power) + 1;
052                                bucket = buckets[idx];
053                                if (value >= bucket.getMax()) {
054                                        bucket = buckets[idx + 1];
055                                }
056                        }
057                }
058                return bucket;
059        }
060
061        /**
062         * {@inheritDoc}
063         * <p/>
064         * Used during quantiles computation to do exponential regression over one bucket.
065         */
066        protected double estimateQuantile(Bucket bucket, double expectedCount, double lastCount) {
067                return bucket.getMin() + (bucket.getMax() - bucket.getMin()) * Math.exp(Math.log(expectedCount - lastCount) / Math.log(bucket.getCount()));
068        }
069}