views:

184

answers:

5

As a diagnostic, I want to display the number of cycles per second in my app. (Think frames-per-second in a first-person-shooter.)

But I don't want to display the most recent value, or the average since launch. What I want to calculate is the mean of the last X values.

My question is, I suppose, about the best way to store these values. My first thought was to create a fixed size array, so each new value would push out the oldest. Is this the best way to do it? If so, how would I implement it?

EDIT: Here's the class I wrote: RRQueue. It inherits Queue, but enforces the capacity and dequeues if necessary.

+11  A: 

The easiest option for this is probably to use a Queue<T>, as this provides the first-in, first-out behavior you're after. Just Enqueue() your items, and when you have more than X items, Dequeue() the extra item(s).

Reed Copsey
Queue is definitely the way to go. Upvote!
ehdv
Would I have to copy to an array to get the mean of all the values?
Tom Wright
@Tom: No, the .NET generic queue implements `IEnumerable<T>` so you can just enumerate over the elements to calculate your mean.
Ron Warholic
If you're using .NET 4.0 (possibly 3.5) you should be able to simply call the `.Sum<T>()` and `.Count<T>()` extension methods directly on the Queue. If you use this idiom a lot, it is trivial to create a `.Average<T>()` extension method yourself.
drharris
@drharris: There is an Average<>() LINQ method for most types. Just call it directly: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.average.aspx
Reed Copsey
@Tom: Just do: double average = myQueue.Average(); // If you're using Queue<double>
Reed Copsey
My bad on that. For some reason Average doesn't show up in my intellisense but allows me to use it with no error. Now that's a new one.
drharris
@drharris: It isn't implemented for IEnumerable<T>, but rather IEnumerable<double/int/etc> - since it needs a specific type to compute upon. That may be why you aren't seeing it...
Reed Copsey
A: 

Keep an index where your next one goes. I'm not familiar with C# syntax, so here's a mock-up in Java. I'll leave it as an exercise to you to handle the case where the array is not yet populated.

class MovingArray {
    int[] values;
    int index;

    public MovingArray(int size) {
        values = new int[size];
        index = 0;
    }

    void add(int value) {
        values[index] = value;
        index = (index+1) % values.length;
    }

    float average() {
        int sum = 0;
        for(int i : values) sum += i;
        return ((float)sum)/values.length;
    }
}
glowcoder
This doesn't solve the issue of getting rid of old data, and is basically just a re-creation of an Array class, only with an Average() method.
drharris
I think the original intention was to also put (in add(int value)) something that resets index to 0 when index==values.Length. That would allow this to function correctly, and remove old values.
Reed Copsey
This does solve the issue. You store the (framerate?) via the add method. It replaces the old data. I did make a mistake that I thought I had edited before but it must not have saved where it doesn't reset the index, which I will fix accordingly.
glowcoder
A: 

If you need the fastest implementation, then yes, a fixed-size array ()with a separate count would be fastest.

Stephen Cleary
+8  A: 

A simple but fast implementation:

// untested

int[] values = new int [10];  // all 0's initially
int sum = 0;
int pos = 0;

void AddValue (int v)
{
   sum -= values[pos];  // only need the array to subtract old value
   sum += v;
   values[pos] = v;     
   pos = (pos + 1) % values.length;    
}

int Average()
{
   return sum / values.length;
}
Henk Holterman
+1  A: 

You should take a look at the performance monitoring built into Windows :D.

MSDN

The API will feel a bit wonky if you haven't played with it before, but it's fast, powerful, extensible, and it makes quick work of getting usable results.

Aaron
Thanks Aaron. Does look interesting, but perhaps overkill for what I need.
Tom Wright