Reputation: 2910
string[] strArray = new string[10] { "21.65", "30.90", "20.42", "10.00", "14.87", "72.19", "36.00", "45.11", "18.66", "22.22" };
float temp = 0.0f;
Int32 resConvert = 0;
Int32 resCast = 0;
for (int i = 0; i < strArray.Length; i++)
{
float.TryParse(strArray[i], out temp);
resConvert = Convert.ToInt32(temp * 100);
resCast = (Int32)(temp * 100);
Console.WriteLine("Convert: " + resConvert + " ExplCast: " + resCast);
}
Ans :
Convert: 2165 ExplCast: 2164 // ??
Convert: 3090 ExplCast: 3089 // ??
Convert: 2042 ExplCast: 2042
Convert: 1000 ExplCast: 1000
Convert: 1487 ExplCast: 1486 //??
Convert: 7219 ExplCast: 7219
Convert: 3600 ExplCast: 3600
Convert: 4511 ExplCast: 4511
Convert: 1866 ExplCast: 1865 //??
Convert: 2222 ExplCast: 2221 //??
Why the value differs sometimes while doing Explicit Cast , but not always. Any reason ?
Upvotes: 14
Views: 4752
Reputation: 39600
Convert.ToInt32
rounds to the nearest integer, the direct cast just truncates the number.
So, if you, due to floating point imprecision, have a value of 2165.99999whatever
instead of 2165.0
, the direct cast truncates all after the floating point, while Convert.ToInt32
rounds to the nearest integer.
Example:
22.22f * 100.0f
results in something like 2221.99993133544921875
.
So Convert.ToInt32
will round it up to the expected value 2222
, while the cast will truncate it to 2221
.
45.11f * 100.0f
on the other hand results in about 4511.00006103515625
,
which Convert.ToInt32
rounds down, which results in 4511
, the same result as when casting directly.
Upvotes: 4
Reputation: 1284
Calling Convert.ToInt32 is like calling:
(int) Math.Round(floatValue, 0);
Direct Casting is like calling
(int) Math.Floor(float);
Floor always gives you a value less than or equal to the value you supply in the argument. Floating point representations are not "precise". So 21.65 is probably represented as 21.649999 or similar since there is not enough precision.
So: 21.65 *100 = 2164.9999 Flooring this value should give you an integer which is smaller than or equal to 2164.9 ... ie: 2164
Rounding 2164.99 on the other hand would give you: 2165
You can see the effect here:
Console.WriteLine(Math.Round(21.65f*100)); //2165
Console.WriteLine(Math.Floor(21.65f*100)); //2164
Using doubles instead of float's (more precision, but still not infinite):
Console.WriteLine(Math.Round(21.65d*100)); //2165
Console.WriteLine(Math.Floor(21.65d*100)); //2165
Upvotes: 1
Reputation: 8851
Following from Botz3000 answer, Relevent sections from MSDN:
Convert.ToInt32 Method (Single)
Return Value Type: System.Int32 value, rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
Explicit Numeric Conversions Table
•When you convert from a double or float value to an integral type, the value is rounded towards zero to the nearest integral value. If the resulting integral value is outside the range of the destination value, the result depends on the overflow checking context. In a checked context, an OverflowException is thrown, while in an unchecked context, the result is an unspecified value of the destination type.
Upvotes: 2
Reputation: 86698
To take one example, 21.65 in float
format is actually represented by a number like 21.6499999. The Convert.ToInt32
rounds the number to the nearest integer, yielding 21.65, while the explicit cast (Int32)
just truncates (rounding toward zero), so you get 21.64.
If you want the floating point numbers to be represented in the computer the same way they look printed out, use decimal
instead of float
or double
.
Upvotes: 9
Reputation: 16802
I think you will find the problem is caused by inaccuracies with floating point precision, specifically using a float
. You will find the issue disappears when using a decimal
. There is a really good answer on the differences between decimal and double (and float) here: decimal vs double! - Which one should I use and when?
Upvotes: 1