也许是一个无用的问题:
public static double Average<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int> selector
)
上述方法引发的异常之一也是OverflowException:序列中元素的总和大于Int64.MaxValue。
我认为出现这种异常的原因是使用类型为long
的变量S计算平均值的总和?但是既然返回值是double
类型的,为什么设计者不选择使S也是double
类型的呢?
感谢
因为这个特定的重载知道您从int
值开始,所以它知道您没有使用十进制值。将每个值转换为double
,然后将double
值相加可能效率较低,而且如果您有足够大的值集合,则肯定会面临浮点不精确问题。
更新
我刚刚做了一个快速基准测试,平均double
s的时间大约比平均int
s的时间长50%。
首先,我注意到,除非超过long的边界,否则不会出现异常。你打算怎么做?每个int最多可以是20亿,一个long的顶部大约是80亿,所以这意味着你必须至少取40多亿int的平均值才能触发异常。这是你经常要解决的问题吗?
为了论证起见,假设是这样的。用双精度运算会失去精度,因为双精度运算被四舍五入到小数点后十五位左右。手表:
using System;
using System.Collections.Generic;
static class Extensions
{
public static double DoubleAverage(this IEnumerable<int> sequence)
{
double sum = 0.0;
long count = 0;
foreach(int item in sequence)
{
++count;
sum += item;
}
return sum / count;
}
public static IEnumerable<T> Concat<T>(this IEnumerable<T> seq1, IEnumerable<T> seq2)
{
foreach(T item in seq1) yield return item;
foreach(T item in seq2) yield return item;
}
}
class P
{
public static IEnumerable<int> Repeat(int x, long count)
{
for (long i = 0; i < count; ++i) yield return x;
}
public static void Main()
{
System.Console.WriteLine(Repeat(1000000000, 10000000).Concat(Repeat(1, 90000000)).DoubleAverage());
System.Console.WriteLine(Repeat(1, 90000000).Concat(Repeat(1000000000, 10000000)).DoubleAverage());
}
}
在这里,我们用二重算术平均两个序列:一个是{十亿,十亿,十亿…1000万次…十亿,一,一…9000万次},另一个是与第一个和最后一个相同的序列。如果你运行代码,你会得到不同的结果。差异不大,但不同,而且序列越长,差异就会越来越大。长算术是精确的;双重算术可能会对的每个计算进行四舍五入,这意味着巨大的错误可能会随着时间的推移而累积。
只对int执行操作会导致浮点舍入误差的累积,这似乎非常出乎意料。这是在浮点运算时所期望的,但在int运算时则不然。