Enumerable.Average和OverflowException

时间:2011-04-19 19:29:34

标签: c# linq

也许是一个无用的问题:

public static double Average<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int> selector
)

上述方法抛出的异常之一也是 OverflowException:序列中元素的总和大于Int64.MaxValue。

我假设这个例外的原因是使用long类型的变量 S 来计算平均值的总和?但由于返回值的类型为double,为什么设计师不选择将 S 设为double类型?

谢谢

2 个答案:

答案 0 :(得分:7)

因为这个特定的重载知道你开始使用int值,所以它知道你没有使用小数值。将每个值转换为double,然后将double值加在一起可能会降低效率,如果您有足够大的集合,肯定会让您面临浮点不精确问题的可能性价值观。

更新

我只是做了一个快速的基准测试,它的大约延长了50% 超过两倍平均double和平均{{} 1}} S上。

答案 1 :(得分:7)

首先,我注意到在你超过长度的界限之前不会出现异常。你打算怎么做?每个int最多约为20亿,而long的顶部约为80亿,因此这意味着您必须采用最少40亿以上的平均值才能触发异常。这是你经常需要解决的问题吗?

假设为了争论而存在。在双精度数中进行数学运算会失去精度,因为双精度算术四舍五入到大约十五个小数位。观看:

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

这里我们用双算术平均两个系列:一个是{十亿,十亿,十亿......一千万......十亿,一,一......九千万次},一个是是与第一个相同的顺序,最后数十亿。如果运行代码,则会得到不同的结果。差别不大,但不同,序列越长,差异就越大。长算术是准确的; 每次计算都会对双重算术进行舍入,这意味着大量错误会随着时间的推移而累积。

单独执行操作会导致浮点舍入误差累积,这似乎非常意外。这是在对浮点数进行操作时所期望的那种事情,但不是在使用整数时进行的操作。