blade
blade

Reputation: 12894

How to cast float to int in C# so that it outputs the same value as float.ToString()?

Calling ToString() on imprecise floats produces numbers a human would expect (eg. 4.999999... gets printed as 5). However, when casting to int, the fractional part gets dropped and the result is an integer decremented by 1.

float num = 5f;
num *= 0.01f;
num *= 100f;
num.ToString().Dump(); // produces "5", as expected
((int)num).ToString().Dump(); // produces "4"

How do I cast the float to int, so that I get the human friendly value, that float.ToString() produces?

I'm using this dirty hack:

int ToInt(float value) {
    return (int)(value + Math.Sign(value) * 0.00001);
}

..but surely there must be a more elegant solution.


Edit: I'm well aware of the reasons why floats are truncated the way they are (4.999... to 4, etc.) The question is about casting to int while emulating the default behavior of System.Single.ToString()

To better illustrate the behavior I'm looking for:

-4.99f should be cast to -4
4.01f should be cast to 4
4.99f should be cast to 4
4.999999f should be cast to 4
4.9999993f should be cast to 5

This is the exact same behavior that ToString produces.

Try running this:

float almost5 = 4.9999993f;
Console.WriteLine(almost5); // "5"
Console.WriteLine((int)almost5); // "4"

Upvotes: 0

Views: 3137

Answers (3)

blade
blade

Reputation: 12894

So far the best solution seems to be the one from the question.

int ToInt(float value) {
    return (int)(value + Math.Sign(value) * 0.000001f);
}

This effectively snaps the value to the closest int, if the difference is small enough (less than 0.000001). However, this function differs from ToString's behavior and is slightly more tolerant to imprecisions.

Another solution, suggested by @chux is to use ToString and parse the string back. Using Int32.Parse throws an exception when a number has a decimal point (or a comma), so you have to keep only the integer part of the string and it may cause other troubles depending on your default CultureInfo.

Upvotes: 0

user1672994
user1672994

Reputation: 10849

0.05f * 100 is not exactly 5 due to floating point rounding (it's actually the value 4.999998.... when expressed as a float

The answer is that in the case of (int)(.05f * 100), you are taking the float value 4.999998 and truncating it to an integer, which yields 4.

So use Math.Round. The Math.Round function rounds a float value to the nearest integer, and rounds midpoint values to the nearest even number.

    float num = 5f;
    num *= 0.01f;
    num *= 100f;
    Console.WriteLine(num.ToString());
    Console.WriteLine(((int)Math.Round(num)).ToString());

Upvotes: 1

apocalypse
apocalypse

Reputation: 5884

Maybe you are looking for this:

Convert.ToInt32(float)

source

Upvotes: 2

Related Questions