【问题标题】:List sum too large, throwing overflow exception列表总和太大,抛出溢出异常
【发布时间】:2018-10-03 18:01:14
【问题描述】:

我有一个最多 2 000 000 个素数的列表。这是一个包含近 150 000 个非常大的整数的列表。我想要其中所有数字的总和。这是一个随机的大整数列表,仅供演示:

List<int> numbers = new List<int>();
for (int i = 0; i < 100; i++)
{
    numbers.Add(1000000000);
}
Console.WriteLine(numbers.Sum().ToString());

我收到“算术运算导致溢出”异常。我猜总和太大了,但是将其转换为 Int64 并没有帮助,它仍然会引发相同的异常。

Console.WriteLine(Convert.ToUInt64(numbers.Sum()).ToString());

我什至尝试将总和保存到 Int64 变量中然后使用它,但这也不起作用。

long sum = numbers.Sum();
Console.WriteLine(sum.ToString());

是否有任何数据类型可以容纳这么大的数字,还是我在其他地方犯了错误?感谢您的帮助。

【问题讨论】:

  • 您的号码可能大于int 的容量。我会尝试将其更改为long
  • 这是一种常见的错误模式。在所有尝试中,您将总和更改为 long,但将 sum 更改为 long 并没有帮助,因为这会转换 为时已晚。这会将 final sum 转换为 long,但到那时它已经溢出了!
  • 我们也将这种模式视为:int x = whatever; double percentage = x / 100;x/100int,因此这会转换为双精度为时已晚。你想要的是((double)x)/100x/100.0,这会导致编译器为你插入转换。这个错误有很多变化。

标签: c# .net linq math integer-overflow


【解决方案1】:

在得到总和之前尝试转换为 Int64(长整数):

Console.WriteLine(numbers.Select(x=> (long)x).Sum().ToString());

【讨论】:

  • 150K 非常大的整数可能会溢出甚至 longs。
  • 此解决方案需要将int 转换为long 150 000 次。我怀疑这是一个最佳解决方案
  • @Steve 那么他应该实现一个自定义添加系统,例如一个适用于字符串的系统。
  • 我在考虑 BigInteger,但我应该重新考虑我的评论。添加 150K 次 Int.MaxValue 不会溢出 long MaxValue
  • @Fabjan as China Syndrome 说最好选择List&lt;long&gt; 而不是List&lt;int&gt;,但我认为这是显而易见的,OP 可能已经知道这一点。我想可能这是一个例子,他不能简单地改变类型。我试图对 OP 的代码进行最少的更改,并纠正错误的地方。
【解决方案2】:

问题是您的答案超过 26.5 亿。 将int 更改为Int64

List<Int64> numbers = new List<Int64>();
for (int i = 0; i < 100; i++)
{
    numbers.Add(1000000000);
}
Console.WriteLine(numbers.Sum().ToString());

澄清一个 Int 的最大值大约为 26.5 亿,而 Int64 为数万亿

【讨论】:

  • 我认为这是比进行 150k 转换更好的方法,即使整数对于数字来说是可以的。谢谢!
【解决方案3】:

你可以使用Aggregate方法:

Console.WriteLine(numbers.Aggregate(0L, (c, n) => c + n));

Aggregate 的重载将累加器作为第一个参数
文字 0L 将被视为 long,而不是 int。这将使您免于算术溢出

【讨论】:

    【解决方案4】:

    从 int 到 long 的转换很便宜,有时甚至是免费的。让我们比较五个代码

    long sum = intArr.Select(x => (long)x).Sum(); // 0.95s
    
    long sum = intArr.Sum(x => (long)x); // 0.95s
    
    long sum = longArr.Sum(); // 0.86s
    
    long sum = 0;
    foreach (int x in intArr)
    {
        sum += x; // 0.22s
    }
    
    long sum = 0;
    foreach (long x in longArr)
    {
        sum += x; // 0.23s
    }
    

    经过的时间是 100M 项目。如您所见,如果您关心性能,则转换不是问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-23
      • 2016-03-07
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多