2010-06-22 41 views
8

Là một chẩn đoán, tôi muốn hiển thị số chu kỳ mỗi giây trong ứng dụng của tôi. (Hãy suy nghĩ khung hình mỗi giây trong trò chơi bắn súng góc nhìn thứ nhất.)Mảng đơn giản (di chuyển trung bình) trong C#

Nhưng tôi không muốn hiển thị giá trị gần đây nhất hoặc trung bình kể từ khi ra mắt. Những gì tôi muốn tính toán là giá trị trung bình của các giá trị X cuối cùng.

Câu hỏi của tôi là, tôi giả sử, về cách tốt nhất để lưu trữ các giá trị này. Suy nghĩ đầu tiên của tôi là tạo một mảng kích thước cố định, vì vậy mỗi giá trị mới sẽ đẩy ra giá trị cũ nhất. Đây có phải là cách tốt nhất để làm điều đó không? Nếu vậy, làm thế nào tôi sẽ thực hiện nó?

EDIT: Đây là lớp tôi đã viết: RRQueue. Nó thừa hưởng Hàng đợi, nhưng thi hành khả năng và các giải pháp nếu cần thiết.

CHỈNH SỬA 2: Pastebin thật tuyệt vời. Bây giờ trên a GitHub repo.

Trả lời

16

Tùy chọn dễ dàng nhất cho việc này có thể là sử dụng một số Queue<T>, vì điều này cung cấp hành vi đầu tiên, đầu tiên mà bạn đang theo dõi. Chỉ cần Enqueue() các mặt hàng của bạn và khi bạn có nhiều hơn X mặt hàng, Dequeue() (các) vật phẩm bổ sung.

+0

Queue chắc chắn là con đường để đi. Upvote! – ehdv

+0

Tôi có phải sao chép vào một mảng để lấy giá trị trung bình của tất cả các giá trị không? –

+0

@Tom: Không, hàng đợi chung .NET thực hiện 'IEnumerable 'do đó bạn có thể chỉ liệt kê các phần tử để tính giá trị trung bình của bạn. –

1

Nếu bạn cần triển khai nhanh nhất, thì có, một mảng có kích thước cố định() với số lượng riêng biệt sẽ là nhanh nhất.

13

Một thực hiện đơn giản nhưng nhanh:

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

Một cải tiến nhỏ (chủ quan): 'sum + = v - values ​​[pos]; giá trị [pos ++] = v; pos% = values.length; '. – heltonbiker

+0

(bạn cũng có thể có một trường precomputed 'đôi divisor = 1.0/values.length' và sau đó' return sum * divisor' kể từ khi phân chia là đắt hơn nhân, nhưng điều này đã khá hoang tưởng, tôi thừa nhận ...) – heltonbiker

+1

_since phân chia đắt hơn phép nhân_ chỉ đúng với phần cứng đơn giản/cũ hơn. Tôi sẽ để lại tất cả các tối ưu hóa vi mô cho (các) trình biên dịch. –

0

Bạn nên hãy nhìn vào công tác giám sát hoạt động xây dựng trong Windows: D.

MSDN

API sẽ cảm thấy một chút rung rinh nếu bạn đã không chơi với nó trước, nhưng nó nhanh chóng, mạnh mẽ, có thể mở rộng, và nó làm cho công việc nhanh chóng nhận được kết quả có thể sử dụng.

+0

Cảm ơn Aaron. Có vẻ thú vị, nhưng có lẽ quá mức cần thiết cho những gì tôi cần. –

1

Có thể sử dụng một bộ lọc:

trung bình = 0,9 * trung bình + 0.1 * giá trị nơi 'giá trị' là đo gần đây nhất

Vary với 0,9 và 0,1 (miễn là tổng của các hai là 1)

Đây không phải là chính xác trung bình, nhưng nó lọc ra gai, transients, vv, nhưng không yêu cầu mảng để lưu trữ.

Greetings, Karel

+0

Đối với các ứng dụng mà không cần tính chính xác toán học chính thức, mà là hành vi làm mịn mong muốn, ý tưởng này chắc chắn đáng xem! – heltonbiker

0

thực hiện của tôi:

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

sử dụng:

private RoundRobinAverage avg = new RoundRobinAverage(10);\ 
... 
var average = avg.Calc(123); 
Các vấn đề liên quan