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
- 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
- If the sum of two negative numbers yields a non-negative result, the sum has overflowed.
As for Rule #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
Looking for a Command Line Argument Parser for .Net
Find the Next Tcp Port in .Net
Visual Studio Designer in X64 Doesn't Work
Vb.Net Equivalent to C# Var Keyword
Read Appsettings JSON Values in .Net Core Test Project
Cssrewriteurltransform with or Without Virtual Directory
Connect to Active Directory via Ldap
Photo Capture on Windows Store App for Windows Phone
Algorithm for Intersection of 2 Lines
Get Substring - Everything Before Certain Char
Where to Find "Microsoft.Visualstudio.Testtools.Unittesting" Missing Dll
How to I Apply Filter While Paginating in ASP.NET MVC and Entity Framework
How to Test Database-Related Code with Nunit
Possible to Access MVC Viewbag Object from JavaScript File
How to Show a Image in Database in the Image Control of ASP.NET