2010-06-22 13 views
8

Jako narzędzie diagnostyczne chcę wyświetlić liczbę cykli na sekundę w mojej aplikacji. (Pomyśl klatek na sekundę w strzelance pierwszoosobowej).Prosta macierz okrągła (ruchoma średnia) w języku C#

Ale nie chcę wyświetlać najnowszej wartości lub średniej od czasu uruchomienia. To, co chcę obliczyć, jest średnią ostatnich wartości X.

Moje pytanie brzmi, jak przypuszczam, na temat najlepszego sposobu przechowywania tych wartości. Moją pierwszą myślą było stworzenie tablicy o stałym rozmiarze, więc każda nowa wartość wypchnie najstarszą. Czy to najlepszy sposób na zrobienie tego? Jeśli tak, w jaki sposób mogę go wdrożyć?

EDYCJA: Oto klasa, którą napisałem: RRQueue. Dziedziczy kolejkę, ale w razie potrzeby wymusza pojemność i piszę.

EDYCJA 2: Pastebin jest tak passé. Teraz na a GitHub repo.

Odpowiedz

16

Najprostszą opcją jest prawdopodobnie użycie Queue<T>, ponieważ zapewnia to pierwsze, pierwsze wyjście, którego szukasz. Po prostu Enqueue() swoje przedmioty, a gdy masz więcej niż X przedmiotów, Dequeue() dodatkowych przedmiotów.

+0

Kolejka jest zdecydowanie do zrobienia. Awansuj! – ehdv

+0

Czy muszę skopiować do tablicy, aby uzyskać średnią wszystkich wartości? –

+0

@Tom: Nie, ogólna kolejka .NET implementuje 'IEnumerable ', więc można po prostu wyliczyć elementy, aby obliczyć średnią. –

1

Jeśli potrzebujesz najszybszej implementacji, to tak, tablica o stałym rozmiarze() z oddzielną liczbą będzie najszybsza.

13

Prosty, ale szybka realizacja:

// 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

Niewielka (subiektywna) poprawa: 'sum + = v - values ​​[pos]; wartości [pos ++] = v; pos% = values.length; '. – heltonbiker

+0

(również możesz mieć wstępnie obliczone pole 'double divisor = 1.0/values.length', a następnie' return sum * divisor', ponieważ podział jest droższy niż mnożenie, ale jest to już dość paranoiczne, przyznaję ...) – heltonbiker

+1

_since podział jest droższy niż mnożenie_ jest prawdą tylko dla prostego/starszego sprzętu. Pozostawiłbym wszystkie te mikrooptymalizacje kompilatorowi (s). –

0

Należy przyjrzeć monitorowania wydajności wbudowany w Windows: D.

MSDN

API poczują się nieco słaby, jeśli nie grałeś z nim wcześniej, ale jest szybki, mocny, rozszerzalny, a to sprawia, szybką pracę uzyskanie użytecznych wyników.

+0

Dzięki Aaron. Wygląda interesująco, ale może przesadzić z tym, czego potrzebuję. –

1

Ewentualnie zastosować filtr:

średni = 0,9 * średnia ± 0,1 * Wartość gdy „wartość” jest ostatni pomiar

zmieniać się wraz z 0,9 i 0,1 (pod warunkiem, suma tych dwa to 1)

To nie jest dokładnie średnia, ale odfiltrowuje skoki, transjenty itp., ale nie wymaga tablic do przechowywania.

Pozdrowienia, Karel

+0

W przypadku aplikacji, w których formalna poprawność matematyczna nie jest potrzebna, ale pożądane zachowanie wygładzające, pomysł ten z pewnością warto rzucić okiem! – heltonbiker

0

moja realizacja:

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; 
    } 
} 

Wykorzystanie:

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