int conversion gives bad results !

Hello !

I discovered an abominable error on a simple division. The problem is quite simple:
5/0.2 = 25, right ?

Well, by using float we have no problem
5f / 0.2f ------> 25. Great

But try to make…
(int) (5f / 0.2f)------- > and you’ll get 24 !! The system loses a number ! And with it, I’m lost as well.

Anyone knows how to fix this unspeakable bug ?
Thank you.

Even others have answered the question already I’d like to mention a few things.

First of all if you are surprised by this result I highly recommend to watch this numberphile video. Once you understand that floating point numbers will never really be accurate except for some special numbers you should always keep that in mind when you want to convert it into an integer.

Note that casting a floating point value to an integer will actually not round down but rounds towards 0. So a value of “1.5” is casted to “1” but a value of “-1.5” is casted to “-1” (so rounded up). Unity provides several methods to perform rounding. First there’s Mathf.Floor and Mathf.Ceil. Those are the equivalent functions from actual math. Floor will always round down while Ceil will always round up. Though we also have the Mathf.Round method which rounds down if the value is below 0.5 and rounds up if it’s above. 0.5 is a special case I won’t go into detail here.

In addition to those 3 methods Unity also provides another set of those methods which directly perform an int conversion for you. Specifically Mathf.RoundToInt, Mathf.FloorToInt and Mathf.CeilToInt. If you perform a floating point calculation where the result would be very close to a whole number, you should always use RoundToInt to be on the safe side. Because if the value of 24.999999 or 25.000001 both would come out at 25

int val = Mathf.RountToInt(5f / 0.2f);

Unity, C# and almost all other programming languages just use the hardware implementation of floating point numbers as it’s defined in the IEEE 754 standard. It specifically defines 2 types: 32 bit (single precision floating point numbers) and 64 bit (double precision floating point numbers). In .NET they are called System.Single and System.Double. However C# has two alias names for those types we all know: float (==System.Single) and double (System.Double).

If you want to quickly explore how 32 bit floating point numbers work under the hood, have a look at this online converter. If you think you want / need to convert or examine those numbers more in detail you might want to have a look at my little editor window which provides a similar functionality but also for double and integer values.

It’s not a bug. When you are using floats, you are by definition only intested in lengths/weights/scalers up to an approximate value, where being over or under by 2^(-22) is acceptable. In your case, you are complaining that 24.99999 is being cast to int 24. That’s not a bug with the system or the language, it’s a bug with your code.

If you need to round to the NEAREST int, then use Mathf.RoundToInt, or something like that.

Strictly speaking, you shouldn’t even assume that the statement

int x = (int)(25f); // could assign 24 or 25 to x

will define x as 25. Casting to int will always round towards zero, and it’s possible that the closest float that the compiler will find to 25f is in fact 24.99999 (remember it works in binary, and my examples have been in decimal).

I suspect x would be 25 in this case, because for small integers, you can exactly represent them with floats, but for larger integers, that wouldn’t be true: e.g. int x = (int)(9876543f); might return 9876540, for example.

If you have a float which is meant to be an int, such as 25f, or 5/(0.2f), then one approach would be to define

int x = (int)(25f + 0.0001f);

to stop the potential rounding error.

I don’t know how C# handles floats, but if you look at how 32 bit floats (“single-precision”) work in C, you’ll see what I’m talking about: Single-precision floating-point format - Wikipedia

It’s very important that the cast will occur before the division, so you can store division operation into a variable and then cast that variable to int.

float r = 5f / 0.2f;
(int)(r)