As I looked closer I noticed that all of the variables in my calculation were integers. A ha! .Net was rounding stuff for me, using its default Banker's Rounding system.
If you are unfamiliar with Banker's Rounding, or aren't a banker, then this way of rounding may seem insane to you. Let me explain. In Banker's Rounding everything works just like in regular rounding, except when dealing with halves. So anything less than .5 will always round down and anything greater than .5 will always round up. But when we have exactly .5 then we round to the closest even number. You are probably used to .5 always rounding up. This is a little known, yet extremely important behavior and I hope to have saved you some heartache. Lets see some Bankers Rounding in action:
1.49 ==> 1
1.50 ==> 2
2.50 ==> 2
2.51 ==> 3
Back to my issue. I needed a way to always round up, no matter what the decimal. Enter the Math.Ceiling function. The Math.Ceiling function returns the next whole number greater than the decimal that you started with. Here it is in action:
System.Math.Ceiling(1.0) ==> 1
System.Math.Ceiling(1.3) ==> 2
Alternatively, if you want to always round down, you could use the Math.Floor function. It returns the next lowest whole number from the starting decimal.
System.Math.Floor(2.0) ==> 2
System.Math.Floor(1.9) ==> 1