You wouldn’t have thought that such as basic operation as rotary a double into an integer would be so poorly understood, but it is. There are three basic approaches in .Net:
- Explicit casting, i.e. (int)x
- Format, by String.Format, or x.ToString(formatString)
- Exchange.ToInt32
What’s critical to realise is that all of these do different things:
var testCases = new[] {0.4, 0.5, 0.51, 1.4, 1.5, 1.51};
Console.WriteLine("Input Cast {0:0} Exchange.ToInt32");
foreach (var testCase in testCases)
{
Console.WriteLine("{0,5} {1,5} {2,5:0} {3,5}", testCase, (int)testCase, testCase, Exchange.ToInt32(testCase));
}
Input Cast {0:0} Exchange.ToInt32 0.4 0 0 0 0.5 0 1 0 0.51 0 1 1 1.4 1 1 1 1.5 1 2 2 1.51 1 2 2
As my basic test above shows, just casting is the equivalent of Math.Floor – it looses the fraction. This surprises some people.
But look again at the consequences for 0.5 and 1.5. By a format string rounds up[1], to 1 and 2, whereas by Exchange.ToInt32 performs bankers rounding[2] (rounds to even) to 0 and 2. This surprises a lot of people, and you’d be forgiven for missing it in the doco (here vs. here):
Even more fascinating is that PowerShell is different, in that the [int] cast in PowerShell is the same as a Exchange.Int32, not a Math.Floor():
> $testCases = 0.4,0.5,0.51,1.4,1.5,1.51> $testCases | % { "{0,5} {1,5} {2,5:0} {3,5}" -f $_,[int]$_,$_,[Exchange]::ToInt32($_) }
Input Cast {0:0} Exchange.ToInt32 0.4 0 0 0 0.5 0 1 0 0.51 1 1 1 1.4 1 1 1 1.5 2 2 2 1.51 2 2 2
This is a fantastic gotcha, since normally I’d use PowerShell to test this kind of behaviour, and I’d have seen the incorrect thing (note to self: use LinqPad more)
[1] More precisely it rounds away from zero, since negative numbers round to the better negative number.
[2] According to Wikipedia bankers rounding is a bit of a misnomer for ‘round to even’, and even the MSDN doco on Math.Round seems to have stopped by the term.

Check it out:Cup(Of T)
Answers Rating