可枚举.Average和OverflowException



也许是一个无用的问题:

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运算时则不然。

相关内容

  • 没有找到相关文章

最新更新