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}