patternjavaMinor
Calculating running average in Java
Viewed 0 times
calculatingrunningaveragejava
Problem
I have a library which makes HTTP calls to my service. I was trying to calculate running average of how much time my service is taking on an average.
Here is the core logic of how I am calculating "running average":
Is there any better/optimized way to do the same thing? I want to make sure this running average calculation is fast since this library runs under very heavy load so this should not increase the overall latency.
Here is the core logic of how I am calculating "running average":
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.Queue;
public class MovingAverage {
private final Queue window = new LinkedList();
private final int period;
private BigDecimal sum = BigDecimal.ZERO;
public MovingAverage(int period) {
this.period = period;
}
public void add(BigDecimal num) {
sum = sum.add(num);
window.add(num);
if (window.size() > period) {
sum = sum.subtract(window.remove());
}
}
public BigDecimal getAverage() {
if (window.isEmpty()) return BigDecimal.ZERO;
BigDecimal divisor = BigDecimal.valueOf(window.size());
return sum.divide(divisor, 2, RoundingMode.HALF_UP);
}
}Is there any better/optimized way to do the same thing? I want to make sure this running average calculation is fast since this library runs under very heavy load so this should not increase the overall latency.
Solution
I created a ring buffer variant for this answer. It was loosely based upon this question and performs considerably better so it may be beneficial to others; note though that it has not been checked for equivalence (and it uses
float instead of BigDecimal):public class MovingAverage {
private final float[] window;
private float sum = 0f;
private int fill;
private int position;
public MovingAverage(int size) {
this.window=new float[size];
}
public void add(float number) {
if(fill==window.length){
sum-=window[position];
}else{
fill++;
}
sum+=number;
window[position++]=number;
if(position == window.length){
position=0;
}
}
public float getAverage() {
return sum / fill;
}
}Code Snippets
public class MovingAverage {
private final float[] window;
private float sum = 0f;
private int fill;
private int position;
public MovingAverage(int size) {
this.window=new float[size];
}
public void add(float number) {
if(fill==window.length){
sum-=window[position];
}else{
fill++;
}
sum+=number;
window[position++]=number;
if(position == window.length){
position=0;
}
}
public float getAverage() {
return sum / fill;
}
}Context
StackExchange Code Review Q#127542, answer score: 4
Revisions (0)
No revisions yet.