7

I have a list of prime numbers up to 2 000 000. That's a list containing almost 150 000 very large integers. I want a sum of all the numbers in it. Here's a random list of large integers just for demonstration:

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

I'm getting a "Arithmetic operation resulted in an overflow" exception. I guess the sum is too large, but converting it to Int64 didn't help, it still throws the same exception.

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

I even tried saving the sum into Int64 variable and then using it, but this didn't work either.

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

Is there any data type that can hold this large number, or am I making the mistake somewhere else? Thanks for any help.

Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
Milan Vodák
  • 125
  • 1
  • 8
  • 1
    Your number may be larger than what `int` can hold. I would try changing it to `long` – Jaskier Oct 03 '18 at 18:04
  • 5
    This is a common bug pattern. In all your attempts you change the sum to long, but changing the *sum* to `long` doesn't help because that converts *too late*. That converts the *final sum* to long, but by then it has already overflowed! – Eric Lippert Oct 03 '18 at 18:05
  • 1
    We also see this pattern as: `int x = whatever; double percentage = x / 100;` but `x/100` is *int*, so this converts to double *too late*. What you want is `((double)x)/100` or `x/100.0`, which causes the compiler to insert the conversion for you. There are lots of variations on this bug. – Eric Lippert Oct 03 '18 at 18:09

4 Answers4

14

Try casting to Int64 (long) before getting sum:

Console.WriteLine(numbers.Select(x=> (long)x).Sum().ToString());
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • 1
    150K very large integers probably will overflow even longs. – Steve Oct 03 '18 at 18:13
  • 2
    This solution requires to convert `int` to `long` 150 000 times. I doubt that it's an optimal solution – Fabjan Oct 03 '18 at 18:14
  • @Steve well then he should implement a custom adding system, for example one that works for strings. – Ashkan Mobayen Khiabani Oct 03 '18 at 18:15
  • I was thinking about BigInteger, however I should rethink my comment. Adding 150K times Int.MaxValue doesn't overflow a long MaxValue – Steve Oct 03 '18 at 18:16
  • @Fabjan as China Syndrome said its better to choose a `List` instead of `List` but I assumed this is something obvious and OP may already know that. I thought may be this is an example and he can not simply change the type. I have tried to make the least change to OP's code and just correct where it is wrong. – Ashkan Mobayen Khiabani Oct 03 '18 at 18:18
  • Thank you very much! That was the problem. – Milan Vodák Oct 03 '18 at 18:20
  • @Steve I'm sorry, from the example it looks like I have 150k integers with 1 billion value. But their values are only up to almost 2 milion. – Milan Vodák Oct 03 '18 at 18:26
  • Integers are ok to store them but as @Fabjan noted, using Int64 list is probably the way to go, to avoid a lot of converting. – Milan Vodák Oct 03 '18 at 18:46
  • 2
    Just as a note you need at least 4.3 billion integers to oveflow long (and they would not fit into single array anyway). – Antonín Lejsek Apr 10 '21 at 17:35
  • @Steve, Int64.MaxValue / Int32.MaxValue = 4,294,967,298, so no, 150K very large integers are at most 0.00349 % of Int64.MaxValue. – Olivier Jacot-Descombes Oct 22 '22 at 15:02
7

Problem is your answer is over 2.65 billions. Change the int to Int64

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

To Clarify an Int has a max value of 2.65 billion roughly and Int64 is in the trillions

China Syndrome
  • 953
  • 12
  • 24
  • I think this is a better way than doing 150k conversions, even though the integers are alright for the numbers. Thanks! – Milan Vodák Oct 03 '18 at 18:48
5

You can use Aggregate method:

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

This overload of Aggregate take an accumulator as first argument
Literal 0L will be treated as long, not int. This will save you from arithmetic overflow

Aleks Andreev
  • 7,016
  • 8
  • 29
  • 37
2

Conversions from int to long are cheap, sometimes even for free. Lets compare five codes

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
}

elapsed time is for 100M items. As you see, if you care about performace, the conversion is not an issue

Antonín Lejsek
  • 6,003
  • 2
  • 16
  • 18