Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerable.Sum() overflowing

Hey, I'm using the Enumerable.Sum() extension method from LINQ to compute hash codes, and am having a problem with OverflowExceptions when the code gets big. I tried putting the call in an unchecked block, but that didn't seem to help.

The MSDN documentation for the method says it will throw if the value gets too big, but I checked in reflector and this is all there is:

public static int Sum(this IEnumerable<int> source) {
    if (source == null) {
        throw Error.ArgumentNull("source");
    }
    int num = 0;
    foreach (int num2 in source) {
        num += num2;
    }
    return num;
}

Based on this decompilation, I would expect it to either overflow or not depending on the context of the calling code. Why is it overflowing, and how can I get it to stop?

like image 961
Hank Avatar asked Feb 05 '10 16:02

Hank


1 Answers

The code is indeed executing in a C# checked block. The problem is that reflector doesn't properly decompile checked blocks and instead shows them as normal mathmatical operations. You can verify this yourself by creating a checked block, compiling the code and then decompiling it in reflector.

You can also verify this by looking at the IL instead of the decompiled C# code. Instead of the add IL opcode you'll see that the addition occurs with add.ovf. This is the version of add that throws on overflows

L_001a: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
L_001f: stloc.1 
L_0020: ldloc.0 
L_0021: ldloc.1 
L_0022: add.ovf <-- This is an overflow aware addition
L_0023: stloc.0 
L_0024: ldloc.2 

There is no way to get this particular method to not throw on overflow. Your best options are the following

  1. Switch to a larger type such as long
  2. Write your own version of Sum which does not use checked addition
like image 189
JaredPar Avatar answered Nov 09 '22 05:11

JaredPar