Float point error when assigning value as position

Hello,

I am unsure whether or not this is issue if caused by Panda3D or Python itself, but I have not experienced it outside of Panda3D. If it is a Python issue, please let me know and I can ask somewhere else if necessary. I have a function, which return linear interpolation, which is round down if necessary. This output is used for assigning a new position for objects. I then check if the new position equals a preset target position. It works fine when I work with integers as targets, but this happened when I used a float:

lerp x:  -0.36
player x:  -0.36000001430511475
target x:  -0.36

This is the console output. The linear interpolation function returns -0.36 and the target is also -0.36 the output from the linear interpolation function is assigned to the player position and it returns -0.36000001430511475 when printed, resulting in it never really reaching the target position.

Here is the linear interpolation function:

def linerp(self, x1, x2, p):
    x = lerp(x1, x2, p)
    if abs(x-x2) < max(p,0.1):
        return x2
    return x

And here I am assigning the values:

#px = current x position
#x = target x position
#p = percentage for linear interpolation
self.player.set_pos(self.linerp(px, x, pc), self.linerp(py, y, pc), self.linerp(pz, z, pc))

I have not tried to round the values when comparing the positions, as I want to solve the issue without a bad workaround. I hope you can help me :slight_smile:

I think that’s a pretty common and general floating-point issue; I recall it appearing not only in Python but also in C++.

In general, comparing floating point values can tricky; I seem to recall that the recommended way is to test not for equality, but for nearness. That is, instead of testing for “myFloat1 == myFloat2”, you might test for “abs(myFloat1 - myFloat2) < 0.00001”, or something similar.

I think that, from Python 3.5 at least, the “math” module provides some functions for such tests.

Thank you! I did not know about that function :slight_smile: I came up with this quick function for comparison if anyone else stumble upon a similar issue:

def compare_dicts(d1, d2, precision):
    for i in d1:
        if i not in d2:
            return False
        elif not math.isclose(d1[i], d2[i], rel_tol=precision):
	    return False
    return True

Right now it only supports dictionaries with float values, but it should be easy to expand.

1 Like

For the record, 0.36 doesn’t actually exist as a binary floating-point number, as can be seen here. When you enter 0.36, a computer will actually store an approximation of that, about 0.36000001430511474609375, which is what you are seeing. Because such numbers are not stored exactly, rounding errors can accumulate, and you cannot make exact comparisons.

A simple example of how this can go wrong:

>>> 0.1 + 0.2 == 0.3
False

For more information, you can check out one of these resources:
https://floating-point-gui.de/basic/
https://blog.reverberate.org/2014/09/what-every-computer-programmer-should.html

1 Like