Best Way to Handle Integer Overflow in C#

Best way to handle Integer overflow in C#?

I haven't needed to use this often, but you can use the checked keyword:

int x = foo();
int test = checked(x * common);

Will result in a runtime exception if overflows. From MSDN:

In a checked context, if an expression produces a value that is
outside the range of the destination type, the result depends on
whether the expression is constant or non-constant. Constant
expressions cause compile time errors, while non-constant expressions
are evaluated at run time and raise exceptions.

I should also point out that there is another C# keyword, unchecked, which of course does the opposite of checked and ignores overflows. You might wonder when you'd ever use unchecked since it appears to be the default behavior. Well, there is a C# compiler option that defines how expressions outside of checked and unchecked are handled: /checked. You can set it under the advanced build settings of your project.

If you have a lot of expressions that need to be checked, the simplest thing to do would actually be to set the /checked build option. Then any expression that overflows, unless wrapped in unchecked, would result in a runtime exception.

Why would you want an integer overflow to occur?

The main time when I want overflow is computing hash codes. There, the actual numeric magnitude of the result doesn't matter at all - it's effectively just a bit pattern which I happen to be manipulating with arithmetic operations.

We have checked arithmetic turned on project-wide for Noda Time - I'd rather throw an exception than return incorrect data. I suspect that it's pretty rare for overflows to be desirable... I'll admit I usually leave the default to unchecked arithmetic, just because it's the default. There's the speed penalty as well, of course...

How to handle overflow in GetHashCode()

Often, when we combine hash codes manually, we do it with xor:

public override int GetHashCode() =>
X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();

See Why is XOR the default way to combine hashes? for details

xor never throws any exception. You can let .Net to combine for you:

public override int GetHashCode() => HashCode.Combine(X, Y, Z);

No overflow exception for int in C#?

C# integer operations don’t throw exceptions upon overflow by default. You can achieve that via the project settings, or by making the calculation checked:

int result = checked(largeInt + otherLargeInt);

Now the operation will throw.

The opposite is unchecked, which makes any operation explicitly unchecked. Obviously, this only makes sense when you’ve got checked operations enabled in the project settings.

Signed integer overflow behaviour

Rule #2 from

http://sandbox.mc.edu/~bennet/cs110/tc/orules.html

is incorrect


  1. If the sum of two negative numbers yields a positive result, the sum has overflowed.

Counter example:

  int a = int.MinValue;
int b = int.MinValue;

unchecked {
// 0
Console.Write(a + b);
}

However, the rule can be simply amended


  1. If the sum of two negative numbers yields a non-negative result, the sum has overflowed.

As for Rule #1

  1. If the sum of two positive numbers yields a negative result, the sum has overflowed.

it's correct one

Integer overflow exception

The reason is when you have int a = 2147483647 + 10; compiler can predict the result of statement(a) and it will know that it causes overflow because both 2147483647 and 10 are constants and their values are known at compile time.

But when you have

int ten = 10;
int b = 2147483647 + ten;

Some other thread (or something else, maybe a wizard, maybe a hazard in memory ...) may have change the value of ten before execution of int b = 2147483647 + ten; statement and the overflow can not be predicted at compile time.

Determine if integer overflow is over or under bounds

Floats are pretty big. Are you expecting the get value to overflow or do you expect the cast to int to overflow? If it's just the cast something similar to the following code might work.

//This answer is wrong, see below.
public int TruncValue
{
get
{
if (Value > (float)int.MaxValue)
{
return int.MaxValue
}
else if (Value < (float)int.MinValue)
{
return int.MinValue
}
else
{
return (int)Value;
}
}
}

Although you might need some additional handling for the edge cases.

Edit - I played around with this in some code and found some behavior that I didn't expect, but apparently it is in the specification.

For example,

var Value = int.MaxValue + int.MaxValue //Ends up returning -2 with no exception in debug mode.
var MaxCalculatedValue = (int.MaxValue + int.MaxValue) * float.MaxValue //Ends up returning something like -3.4... ^38.

You really might need to up cast everything into a double and then check to see if the result is greater than or less than an int.

So it might look something like this:

public float Value
{
get
{
var result = ((double)baseValue + (double)baseAdjustment) * (double)baseMultiplier;
if (result > (double)int.MaxValue)
{
return (float)int.MaxValue)
}
if (result < (double)int.MinValue)
{
return (float)int.MinValue)
}
return (float)result;
}
}


Related Topics



Leave a reply



Submit