HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Calculating running average in Java

Submitted by: @import:stackexchange-codereview··
0
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":

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.