2013-02-12 67 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