When adding 0.1 to 1, you get 1.1, right? For some reason, when doing this in bge, I get values like 1.0999999999…
Is this normal? I’ve never really noticed it before. How do I make it the proper value?
I saw an explanation for this somewhere, but I forget where.
It has something to do with the differences in the way that Python and the BGE itself process numbers. So if you’re working with floats and you want exact values, the best way to do it is to use either only-Python or only-logic for that number.
It is normal. This is the characteristics of the float datatype.
Background: The name “float” is a short of “floating point number” and expresses non-integer numbers with the dynamic precision.
The precision depends on the size of the value to be expressed. E.g. 1 has an higher precision than 1000. As computers do not calculate in decimals but binaries. The precision changes with base(2) rather than base(10). It also means 0.1 as decimal is not necessarily 0.1 as you know it. Because of the precision it might be a bit different than 0.1. this can be 0.100000001 or 0.999999999. Even if 0,1 can be expressed if you calculate you get aberrations due to the precision.
1 + 0.1 ~= 1.0999999999
This is also the reason, why objects far away from the origin (e.g. at 10000,0,0) seams to get visual distortions in Blender. This is due to the reduced precision at this distance.
It’s because floats are stored in binary fractions:
As the example states, 0.125 is a sum of 1/10 + 2/100 + 5/1000. We can also represent it in base two in the same manner (base2 = binary), 0/2 + 0/4 + 1/8. However, not all decimal fractions have exact binary fractions (i.e they’d be represented as an infinite series) so we have to approximate.
This error is usually negligible until you start operating upon floating point values. In addition, Python will round to a certain precision in the display. Again, from the example, 0.1 is not easily represented in base 2, but we round it in the display such that it appears as 1/10. However, when you add another value to it, you can introduce greater error than the precision accounts for, so you see the large trailing numbers.
You can “work around” this by using the fractions module. This will maintain the concept of a numerator and denominator until the final floating point representation is required.
Looking at it practically, the work around involves not relying on the exact precision of floats.
If you want to check if two numbers are equal, it’s best to use integers, or convert your floats in to integers, or round your floats using round()
When comparing floats it’s better to use >= or <= equal to instead of == as this is more likely to get you the result you want (is the health bar empty? is the glass half full or half empty?).
You may also find integers a little faster to work with than floats depending on what you’re doing with them.
If comparing two world positions you can get better precision by using the .to_tuple() function from mathutils.
if bullet.worldPosition.to_tuple(1) == player.worldPosition.to_tuple(1): player.die()
However, this is more useful for functions such as snapping things to a grid than for detecting collisions or occlusions.
With positions, it is generally advisable (as with most floating point numbers) to use a threshold value
if (vec_a - vec_b).length_squared < epsilon: pass