Godot: Vector floating point values are not matching what was assigned to it.

Created on 4 Apr 2018  路  11Comments  路  Source: godotengine/godot

Godot version:

Godot 3.0.2

OS/device including version:

Manjaro Linux 17.1.7

Issue description:

When creating a Vector or assigning numbers to it that have floating point values results in the vector holding a number that is not equal to the original number.

The number in the vector should be the same number that was assigned to it. This has been causing me a few issues and road blocks in my development.

It is possibly the cause or related to these issues:
https://github.com/godotengine/godot/issues/17820
https://github.com/godotengine/godot/issues/17307

Also when trying to compare a number with floating point values to a vector's value it will return false even if they are the same exact number.

Steps to reproduce:

var x = 100.01
var v = Vector3(x, 0, 0)
print( x == v.x)
print(x)
print(v.x)

** Output **

False
100.01
100.010002
var v = Vector2(0, 0, 0)
v.x = 100.05
print(v.x)

** Output **

100.050003
var x = 1.01
var v = Vector2(x , 0)
print(v.x)
print(v.x == x)
print(v.x == 1.01)
v.x = 1.0
print(v.x == 1.0)

** Output **

1.01
False
False
True

* I tested this in Godot 2.1.4 and the issue is similar *
In Godot 2.1.4 a float suffers from this bug where in Godot 3.0.2 the float works correctly but the Vectors are still suffering from this bug.

var x = 100.01
var v = Vector3(x, 0, 0)
print(x)
print(v.x)
print(v.x == x)
print(v.x == 100.01)

** Output **

100.010002
100.010002
True
True
discussion enhancement core

All 11 comments

its because float numbers does no support precise direct comparsion by nature, you should use something like this

func isEqual(v1, v2)
{
    return abs(v1 - v2) < 0.000001
}

Thanks I did not realize this. Perhaps GDScript should do this automatically.
However, the primary issue is with Vectors not holding the exact values that are assigned to them, this is causing issues such as seams in 3d tiles and possibly many other issues like the bugs with SurfaceTool.

However, the primary issue is with Vectors not holding the exact values that are assigned to them

Floating point (in fractional part) have "exact" values for human eyes, on program level they always contains inaccuracy(its their nature) and due its inaccuracy they cannot be correctly compared on equality(just it). But dont panic, this inaccuracy is invisible for human eyes, did you see seams in Minecraft ?
PS. I think about introducing core function which compare two floating point values with user-defined precision(simular to what I showed above).

@K9Kraken Numbers like 1/10 and 1/100 become recurring (infinite) fractions in binary, similar to 1/3 in decimal. You won't be able to store exact value of such number in any binary fixed or floating point format (even in arbitrary-precision one), only as separate numerator/denominator.

Thanks for the response, I was getting confused because I thought "vector.x = float" was the same as "float = float". Previous software I've used stored values in their vectors as floats so the numbers stayed the same when you assigned them.

Also thinking about this I don't think it is related to the issues I linked to above.

Leaving this open as it's not yet clear if there is an bug here (in addition to the expected precision issues of float).

From IRC:

no, there is obviously some loss of precision due to a float/double conversion
while it isn't good to compare doubles for equality, it shouldn't behave worse than C due to a bug :)

Vector3 use single precision floats, Variant (default variable type) uses double precision, both can't represent 100.01, you only get same value out because print have limited output precision.

Single is 100.01000213623046875
Double is 100.0100000000000051159076974727213382720947265625

print only outputs up to 12 decimal digits, see ustring.cpp#L948-L949.

Unfortunately there is no way to have perfectly-precise representations of all decimal numbers in binary floating point formats. However, the solution as @Chaosus mentioned is to use approximate-equality comparison methods.

I have a pull request open here #18992 which does several things to improve approximate equality methods, including changing the Vector, Color, etc, comparison methods to use approximate equality comparisons, and exposing these to GDScript. print(x == v.x) will still fail, but comparing two vectors will work, and print(is_equal_approx(x, v.x)) will also work.

18992 added ways to properly check for equality, and the other half of this issue is a duplicate of #288, as vectors will match assigned values when they use doubles.

Closing as per above comment.

Was this page helpful?
0 / 5 - 0 ratings