Reputation: 60909
I am trying to keep a running average inside of a SharedPreference. Here is my code:
//Get the number of captures
int numberOfCaptures = prefs.getInt(CaptureActivity.NUMBER_OF_CAPTURES, 0);
numberOfCaptures++;
//Calculate the average of all of the captures
int runningAverage = prefs.getInt(CaptureActivity.AVERAGE_BLAST_SCORE, 0);
System.out.println("Running Average: " + runningAverage);
int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;
System.out.println("Blast Score: " + result.getBlastScore());
System.out.println("Number of Captures: " + numberOfCaptures);
System.out.println("Average Blast Score: " + averageBlastScore);
//Save it, so we can get it again if the user captures another swing
prefs.edit().putInt(CaptureActivity.AVERAGE_BLAST_SCORE, averageBlastScore).commit();
prefs.edit().putInt(CaptureActivity.NUMBER_OF_CAPTURES, numberOfCaptures).commit();
It seems like my running average is not getting added properly.
Here it is for 3 runs:
10-28 02:53:13.690: I/System.out(1162): Running Average: 0
10-28 02:53:13.690: I/System.out(1162): Blast Score: 96
10-28 02:53:13.690: I/System.out(1162): Number of Captures: 1
10-28 02:53:13.690: I/System.out(1162): Average Blast Score: 96
10-28 02:53:25.550: I/System.out(1162): Running Average: 96
10-28 02:53:25.550: I/System.out(1162): Blast Score: 99
10-28 02:53:25.550: I/System.out(1162): Number of Captures: 2
10-28 02:53:25.550: I/System.out(1162): Average Blast Score: 97
10-28 02:54:04.720: I/System.out(1162): Running Average: 97
10-28 02:54:04.720: I/System.out(1162): Blast Score: 100
10-28 02:54:04.720: I/System.out(1162): Number of Captures: 3
10-28 02:54:04.720: I/System.out(1162): Average Blast Score: 65
By the third run I should have:
Running Average: 295
Average Blast Score: 98.3
I'm not exactly sure what I'm doing wrong.
Upvotes: 0
Views: 478
Reputation: 2617
To keep a running average you don't keep the actual average, you keep the running total and the number of samples, then you calculate the average the usual way, which is total/samples. Therefore for this set you should be keeping these values at each stage..
Samples: 96, 99, 100
Total : 96, Samples : 1 => AVG = 96/1 = 96
Total : 195, Samples : 2 => AVG = 195/2 = 97.5
Total : 295, Samples : 3 => AVG = 295/3 = 98.333
A wrong way stated elsewhere is to always divide by two after the first sample, and simply add the previous average to the new sample. This would result in 99 samples of 100, and a sample of 0 having an average of 50, which is obviously wrong.
I would change your code to something like this
int numberOfCaptures = prefs.getInt(CaptureActivity.NUMBER_OF_CAPTURES, 0);
numberOfCaptures++;
int runningTotal = prefs.getInt(CaptureActivity.RUNNING_TOTAL, 0);
runningTotal += result.getBlastScore();
//Calculate the average of all of the captures
int averageBlastScore = runningTotal / numberOfCaptures;
System.out.println("Blast Score: " + result.getBlastScore());
System.out.println("Number of Captures: " + numberOfCaptures);
System.out.println("Average Blast Score: " + averageBlastScore);
//Save it, so we can get it again if the user captures another swing
prefs.edit().putInt(CaptureActivity.RUNNING_TOTAL, runningTotal).commit();
prefs.edit().putInt(CaptureActivity.NUMBER_OF_CAPTURES, numberOfCaptures).commit();
If you insist on storing the running average instead of running total, you are going to have to multiple that average out by samples BEFORE incrementing samples to obtain the previous total, and then proceed from there.
Upvotes: 0
Reputation: 5083
I have noticed a potential flaw in your code - the following line is the culprit:
int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;
Let's consider a scenario where you have 3 scores: 99,98,90
Since you are doing an iterative average operation, the results would look as follows:
Instead, after the second iteration you should be dividing by 2 each time.
Another way to tackle this would be to wait until you have received all the scores and then divide the total by the number of captures.
Upvotes: 0
Reputation: 99144
Look at this line:
int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;
What do you expect to happen after, say, the 100th iteration?
You should find the average by adding up scores and dividing by the number of captures:
int sumBlastScore = prefs.getInt(CaptureActivity.SUM_BLAST_SCORE, 0) + result.getBlastScore();
int averageBlastScore = sumBlastScore/numberOfCaptures;
System.out.println("Running Average: " + averageBlastScore);
Upvotes: 1