gdhc21
gdhc21

Reputation: 107

How to create a moving average in Java

I need a program that will calculate the moving average of a set of numbers (I used 4, 9, 3.14, 1.59, 86.0, 35.2, 9.98, 1.00, 0.01, 2.2, and 3.76). When I run this, it prints out "17.859999999999996" nine times. Do you guys see any errors?

import java.util.*;

public class MovingAverage
{
    public static void main(String args[])
    {
        Scanner scan = new Scanner(System.in);
        // Read in the length of the moving average and the number
        // of data points
        int averageLength = scan.nextInt();
        int numDataPoints = scan.nextInt();
        // Create an array to hold the data points, and another to
        // hold the moving average
        double data[] = new double[numDataPoints];
        double movingAverage[] = new double[numDataPoints];
        // Read in all of the data points using a for loop
        for(int i = 0; i< numDataPoints; i++)
        {
            data[i]=scan.nextDouble();
        }
        // Create the moving average
        for (int i=0; i<numDataPoints; i++) 
        {
            // Calculate the moving average for index i and put
            // it in movingAverage[i]. (Hint: you need a for
            // loop to do this. Make sure not to use i as your
            // loop variable. Also, make sure to handle the
            // case where i is not large enough (when i<averageLength-1). 
            double sum= 0.0;
            for(int j=0; j<numDataPoints; j++)
            {

                sum=sum+data[j];
                movingAverage[i]=sum/j;
            }

        }
        // Print the moving average, one value per line
        for (int i=0; i<numDataPoints; i++)
        {
            System.out.println(movingAverage[i]);
        }
    }
}

Upvotes: 0

Views: 6806

Answers (6)

Dom
Dom

Reputation: 1722

In a moving average, you need to have some kind of window size.

Your window size is averageLength, so it will look something like this:

    if(i <averageLength-1)
    {
        double sum= 0.0;

        for(int j = 0; j < averageLength; j++)
        {
            sum += data[i-j];
        }

        movingAverage[i]=sum/averageLength;
    }

The for loop starts at the current data and goes back averageLength data points and adds them up. You will only have a moving average when you have you have when you have enough data points and the average will be the sum divided by the average length.

Note: Not tested just sudo code, but this is the idea.

Upvotes: 0

Mike Housky
Mike Housky

Reputation: 4069

Without any additional details, you probably need an unweighted moving average. At any point A[i] in the input array A of length N (with 0<=i<N), that's simply the mean of the previous K entries of the array, up to and including A[i]. If there aren't K such values, then average the (i+1) values from A[0] through A[i], inclusive.

A little bit of thought will show you that you don't need to add up all K values every time. Just keep the sum and, when moving to the next point (this is a "moving" average), subtract the value that's being replaced and add the new value that will replace it. (During the first K-1 points, you'll simply add the new value to the sum and increase your counter by 1.)

At any point in this process, the moving average is the current sum divided by the current count value.

Upvotes: 0

BobbyD17
BobbyD17

Reputation: 505

Next time, take the comments about the assignment out of the question before you post it. But since you seem pretty new at this, think about how you would go through the data, and make it do that. You should try to make sure each loop is stopping at the correct point, and remember that if you would stop when there are no more numbers, (like when you are doing the inner loop and you can only get 3 more numbers instead of 4) the program needs to stop too. Make sure your code is checking for this.

Upvotes: 0

porfiriopartida
porfiriopartida

Reputation: 1556

Your inner for is iterating all the array so that's why you always get the same average (the one for the whole array), you should iterate from 0 to the current number of the outer for instead.

Your moving average is being updated based in j of your inner for; that means it will overrides previous values every new loop, this should be inside the outer for instead of the inner one using i as index.

You are dividing sum/j to calculate averages, every new inner loop j you will divide by 0 the first sum. I believe you meant to use j+1 instead, index is not the same as current length

Tips to troubleshoot:

Avoid using variables to loop arrays, you should use array.length instead.

For a matter of reproduce your issue you could give us the isolated problem instead of your current code... ie:

double[] data = new double[] { 1, 5, 8 }; //your real inputs. 
double[] movingAverage = new double[data.length];
for (int i = 0; i < data.length; i++) {
  double sum = 0.0;
  for (int j = 0; j <= i; j++) {
   ...
  }
}

Imagine if the error is in your inputs, how could we believe you really used them?

Upvotes: 1

abiessu
abiessu

Reputation: 1927

You are looping over all the data every time. You should have for(int j=(i>=averageLength?i-averageLength/2:0); j< i+averageLength/2 && j<numDataPoints; j++) (or something similar) for your innermost average.

Also, movingAverage[i]=sum/j; should be modified to handle the case when j is 0. In particular, it should probably be movingAverage[i]=sum/averageLength; and it should be applied to the movingAverage[i] slot outside the averaging loop.

Upvotes: 0

John
John

Reputation: 16007

Since this looks like an assignment, I'll give you a hint.

A moving average has a window. In this case, the width of the window is averageLength. This is the number of points you average over.

You'll need to use averageLength somehow in the loops that create the moving average. You don't now.

Upvotes: 3

Related Questions