float - 7th decimal place not visible toString

I’ve almost gone crazy with this.

Using: Unity 2017.4.1f1 on Windows 10 64bit.

I have a position.z(of Vector3) of a gameObject which prints -5.5.
I do the operation position.z - (-4.5) and I expect -1
But the result is -0.9999995 !

So after a lot of research I wrote this code to
test a theory :

And the console output is this:

Without “F7” the output is -3.5 instead of -3.5000005.
Even with “F7” I can’t print the real value of j.
But the result of j - k is printable…

Based on my theory the position.z is 5.5000005 and not 5.5, so this is why i get this result.
This 0.0000005 may not be significant but it lead to a bug which because of toString() method, Debug.Log didn’t print the real value and it was very difficult to find.

Any idea what’s going on ?

There’s no bug; that’s how floating point works. You are printing the real value. If you don’t want to deal with floating point limitations, use integers instead.

–Eric

The value just can’t be represented as a float, I imagine.

1 Like

Floats have tons of errors involved with them.

For starters… floats are stored in binary in a format like so:

It’s effectively the scientific notation, but base 2 instead of base 10.

So instead of being like 1.3 * 10^-8 = 1.3e-8 = 0.000000013. Where you have the sig value range and the number of digits to move the decimal point by (hence the name ‘float’).

Instead it’s a binary sig value range, and the amount of binary digits to move the binary point.

Now in decimal there are values that are weird… like say 1/3 = 0.333333333333333… Well in binary super common values are repeating… like 0.1dec = 0.0001100110011001100110011001100110011… It’s a repeating value.

But here in lies an issue. A computer has a finite amount of memory. It can’t hold all those 1’s and 0’s. Instead you get 24 binary digits of sig value (23 stored, and 1 implied, because all non-zero binary digits have a leading 1). So a maximum of 24 of those 1’s and 0’s get stored. Meaning you have a value just shy of 0.1… more like 0.09999998.

This is the sort of thing happening to you in your example code.

Floats just work this way.

When you convert a float to string, you should be using format strings to make them look good.

Here is a long article going into all the math and what nots about floating point error:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

1 Like

Thanks everyone for your time and your answers!
I knew that numbers are stored in binnary and I’ve done binary operations in my University, but I didn’t know that sometimes can’t be stored exact like 0.1.I have to read more about it.

For future reference If I want to check if an object is in a exact position (such as pos.z == 5.5) How would I do it ? Do I have to round always the transform values ?

To compare two float and take this error into account I believe you need to do something like this: (sorry for the lack of code tags, on mobile)

If(Mathf.abs(Mathf.abs(value1) - Mathf.abs(value2)) < mathf.epsilon) return true

1 Like
1 Like