2010-06-22 18 views
8

Como diagnóstico, quiero mostrar el número de ciclos por segundo en mi aplicación. (Pensar cuadros por segundo en un tirador en primera persona.)matriz round robin simple (promedio móvil) en C#

Pero no quiero mostrar el valor más reciente, o el promedio desde el lanzamiento. Lo que quiero calcular es la media de los últimos X valores.

Mi pregunta es, supongo, sobre la mejor manera de almacenar estos valores. Lo primero que pensé fue crear una matriz de tamaño fijo, por lo que cada nuevo valor arrojaría la más antigua. ¿Es esta la mejor manera de hacerlo? Si es así, ¿cómo lo implementaría?

EDITAR: Aquí está la clase que escribí: RRQueue. Hereda Queue, pero aplica la capacidad y dequeues si es necesario.

EDIT 2: Pastebin is so passé. Ahora en a GitHub repo.

Respuesta

16

La opción más fácil para esto es, probablemente, utilizar un Queue<T>, ya que esto proporciona el comportamiento de primero en entrar, primero en salir, que está buscando. Solo Enqueue() sus artículos, y cuando tiene más de X artículos, Dequeue() el artículo (s) adicional (es).

+0

cola es definitivamente el camino a seguir. ¡Voto! – ehdv

+0

¿Tendría que copiar a una matriz para obtener la media de todos los valores? –

+0

@Tom: No, la cola genérica .NET implementa 'IEnumerable ' por lo que puede enumerar los elementos para calcular su media. –

1

Si necesita la implementación más rápida, entonces sí, una matriz de tamaño fijo() con un recuento separado sería la más rápida.

13

Un simple pero rápida aplicación:

// 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; 
} 
+0

Una pequeña mejora (subjetiva): 'suma + = v - valores [pos]; valores [pos ++] = v; pos% = values.length; '. – heltonbiker

+0

(también podría tener un campo precalculado 'double divisor = 1.0/values.length' y luego' return sum * divisor' ya que la división es más costosa que la multiplicación, pero esto ya es bastante paranoico, lo admito ...) – heltonbiker

+1

_since la división es más costosa que la multiplicación_ solo es cierto para hardware simple/antiguo. Dejaría todas estas micro optimizaciones al compilador (es). –

0

debería echar un vistazo a la supervisión del rendimiento integrada en Windows: D.

MSDN

La API se sentirá un poco torcidas si no ha jugado con él antes, pero es rápido, potente y extensible, y hace el trabajo rápido de obtener resultados útiles.

+0

Gracias Aaron. Se ve interesante, pero quizás demasiado para lo que necesito. –

1

Posiblemente utilizar un filtro:

promedio = 0.9 * media + 0,1 * valor donde 'valor' es la medición más reciente

variar con los 0,9 y 0,1 (siempre que la suma de estos dos es 1)

Esto no es exactamente un promedio, pero filtra picos, transitorios, etc., pero no requiere arreglos para el almacenamiento.

Saludos, Karel

+0

Para aplicaciones donde no se necesita corrección matemática formal, sino más bien un comportamiento de suavizado deseado, ¡esta idea vale la pena echarle un vistazo! – heltonbiker

0

mi aplicación:

class RoundRobinAverage 
{ 
    int[] buffer; 
    byte _size; 
    byte _idx = 0; 
    public RoundRobinAverage(byte size) 
    { 
     _size = size; 
     buffer = new int[size]; 
    } 

    public double Calc(int probeValue) 
    { 
     buffer[_idx++] = probeValue; 
     if (_idx >= _size) 
      _idx = 0; 

     return buffer.Sum()/_size; 
    } 
} 

uso:

private RoundRobinAverage avg = new RoundRobinAverage(10);\ 
... 
var average = avg.Calc(123); 
Cuestiones relacionadas