2013-02-12 68 views
2

我想計算浮點數組的平均值。我需要使用索引,因爲這是在二進制搜索中,所以頂部和底部會移動。 (大圖我們試圖優化半範圍估計,所以我們不必每次都重新創建陣列)。c#float []平均丟失精度

反正我寫了一個自定義的平均循環,我得到比C#的平均精度2位以下()方法

float test = input.Average(); 

int count = (top - bottom) + 1;//number of elements in this iteration 
int pos = bottom; 
float average = 0f;//working average 
while (pos <= top) 
{ 
    average += input[pos]; 
    pos++; 
} 
average = average/count; 

例如:

 
0.0371166766 - c# 
0.03711666 - my loop 

125090.148 - c# 
125090.281 - my loop

http://pastebin.com/qRE3VrCt

+2

嘗試存儲'average'作爲雙,並在年底轉換爲'float'。 – Servy 2013-02-12 18:32:56

+2

我也會重命名你的累加器'sum',並最終使用一個新的變量'average'。 – CodesInChaos 2013-02-12 18:36:16

+1

浮點數字幾乎總是隻是一個近似值。如果您的平均計算與c#Average()不同,您將得到不同的結果。看看這個:http://stackoverflow.com/questions/4664662/understanding-floatingpoint-problems – Jobo 2013-02-12 18:43:16

回答

3

我得到2位精度較差比C#平均()

沒有,你只失去1顯著位。浮點型只能存儲7位有效數字,其餘的只是隨機噪聲。在這樣的計算中不可避免地會出現舍入誤差,從而失去精度。獲得平衡誤差需要運氣。

避免它的唯一方法是使用更精確的浮點類型來累加結果。不是一個問題,你有可用。這就是爲什麼LINQ的平均方法是這樣的:

public static float Average(this IEnumerable<float> source) { 
     if (source == null) throw Error.ArgumentNull("source"); 
     double sum = 0;   // <=== NOTE: double 
     long count = 0; 
     checked { 
      foreach (float v in source) { 
       sum += v; 
       count++; 
      } 
     } 
     if (count > 0) return (float)(sum/count); 
     throw Error.NoElements(); 
    } 

使用重現與Linq的數量相當的結果顯著數字結果。

2

我d將其重寫爲:

int count = (top - bottom) + 1;//number of elements in this iteration 
double sum = 0; 
for(int i = bottom; i <= top; i++) 
{ 
    sum += input[i]; 
} 
float average = (float)(sum/count); 

這樣你就可以使用高精度累加器,這有助於減少舍入誤差。

btw。如果性能並不重要,你仍然可以使用LINQ來計算陣列片的平均水平:如果適合您的問題

input.Skip(bottom).Take(top - bottom + 1).Average() 

我不能完全肯定,但如果你需要計算許多子陣列的平均值,創建持久性和數組可能會很有用,因此計算平均值只需成爲兩個表查找和一個分區。

+1

最後你需要演員陣容。 – Servy 2013-02-12 18:40:12

1

只是要添加到對話中,使用浮點基元時要小心。

What Every Computer Scientist Should Know About Floating-Point Arithmetic

內浮置未反映在所顯示的值點數存儲的其他至少顯著位(又名:保護比特或保護位)。然而,它們在執行數學運算和平等檢查時被利用。一個常見的結果是,包含0f的變量並不總是爲零。當累加浮點值時,這也會導致精度錯誤。

使用十進制爲您的蓄電池:

  1. 不會有舍入誤差由於衛隊位數
  2. 是一個128位的數據類型(不太可能超過其最大的價值在累加器)。

欲瞭解更多信息: What is the difference between Decimal, Float and Double in C#?

+0

對於採樣數較少的累加器使用十進制是毫無意義的,並且會影響性​​能。 – kwesolowski 2015-07-25 15:14:11