xyz

It's simple (...)

Ok, thanks, I'll give it a try.

Catapult It probably is safe to use. But again, the documentation does not explicitly guarantee it. So we can't be sure. IMHO it should mention how it internally determines if two vectors are equal.

And you're not only an engine user. You're a software developer as well. And every software developer should know how floats operate. That's why the article @Megalomaniak linked is called What Every Programmer Should Know About Floating-Point Arithmetic 😉

Imagine you want to port your code to a different language or need to use a different type of array. In c++ for example, all find() methods for all standard array types always default to using == for comparison.

    xyz

    IMHO it should mention how it internally determines if two vectors are equal.

    I agree with you. Maybe PackedVector2Array should feature a find_approx method. Sorry, just jocking. :-)

    And you're not only an engine user. You're a software developer as well. And every software developer should know how floats operate. That's why the article @Megalomaniak linked is called What Every Programmer Should Know About Floating-Point Arithmetic

    I was quite surprised by the links he/she posted (I said I'm a novice Godot user, not a novice developer).

    Nonetheless, I see very little danger for my code, but I will definitely remember this discussion in case something happens in the future. :-D

      Catapult I was quite surprised by the links he/she posted (I said I'm a novice Godot user, not a novice developer).

      @xyz was the one to bring it up, I just provided the link in response to what I quoted there(you said you were unsure you completely understood what they said). But also the link will be useful for anybody else that stumbles across the topic. 😉

      I did a quick test and it appears that find() in packed arrays indeed uses some epsilon when comparing values. However it can still bite you in the butt when you least expect.
      Consider this piece of code:

      	# add an integer value to float32 array
      	var a = PackedFloat32Array()
      	a.push_back(1)
      	
      	# do some calculations that should result in the same value we started with 
      	a[0] -= 1.1
      	a[0] += 1.1
      	
      	# prints true as expected
      	print(a[0] == 1)
      	
      	# prints true as expected
      	print(is_equal_approx(a[0], 1))
      	
      	# prints 0, the value is fond in the array as expected
      	print(a.find(1))

      Now check this out. Exactly the same code, only that addition/subtraction in our dummy calculation swapped places. The code now behaves differently for seemingly no apparent reason:

      	# add an integer value to float32 array
      	var a = PackedFloat32Array()
      	a.push_back(1)
      	
      	# do some calculations that should result in the same value we started with 
      	a[0] += 1.1
      	a[0] -= 1.1
      	
      	# prints false
      	print(a[0] == 1)
      	
      	# prints true
      	print(is_equal_approx(a[0], 1))
      	
      	# prints -1, the value is NOT found in the array
      	print(a.find(1))

      That's the kind of gotchas I was talking about.

      But there's more 🙂 If you change 1.1 to 1.2 in the second piece of code, things now again work as expected. But if you change it yet again to 1.4 - the bug is back.
      Is my computer possessed by a demon? 😃

        xyz

        That's the kind of gotchas I was talking about.

        Is my computer possessed by a demon?

        Well, you should report something like this to the engine developers, if you have not done it yet. Or you could call an exorcist. ;-)
        [post update: everything written here was meant to be ironic]

        • xyz replied to this.

          Megalomaniak

          if you want I can split the topic into 2 so the float precision topic is a separate one.

          Don't worry, it's ok the way it is. :-)

          Catapult Well, you should report something like this to the engine developers, if you have not done it yet. Or you could call an exorcist. ;-)

          There's nothing to be done about it. It's just the nature of number representation in floating point format. The best we can do is to learn about it and adapt our code to avoid bugs. Although truth be told I haven't tried the exorcist approach yet 🙂

            xyz

            In Godot, all vector/matrix data components are 32 bit floats.

            Many methods and properties in the engine use 32-bit single-precision floating-point numbers instead, equivalent to float in C++, which have 6 reliable decimal digits of precision. For data structures such as Vector2 and Vector3, Godot uses 32-bit floating-point numbers by default, but it can be changed to use 64-bit doubles if Godot is compiled with the precision=double option. (source)

            • xyz replied to this.

              Catapult
              Oh, but they all do behave in precisely this way if you use floats. You just haven't picked the "right" numbers. This is fundamental to floating point representation of real numbers. Think about it. You have finite number of bits to represent infinite number of decimal places. There's no theoretical way to achieve "total" precision. Hence using == with floating point numbers of any precision always comes with this caveat.

              GDScript has nothing to do with this. It happens with floating point arithmetic on the machine code level. So all higher level languages will do the same.

              Here are two examples.

              Python prints False here:

              a = 1
              a += 1.11
              a -= 1.11
              print( a == 1 )

              C++ prints zero here, which is equivalent of false:

              #include <iostream>
              
              int main() {
                 float a = 1.0f;
                 a += 1.11f;
                 a -= 1.11f;
                 
                 std::cout << (a == 1.0f);
              }

              Double precision floats in c++ will produce the same result:

              #include <iostream>
              
              int main() {
                 double a = 1.0;
                 a += 1.11;
                 a -= 1.11;
                 
                 std::cout << (a == 1.0);
              }

                xyz That's fine, but since it is a known problem, any part of any engine (not to mention any software) has always had this kind of problem. You can try to work around the problem, but the problem is deep-rooted one and is always there. And you can't decide to avoid floats, especially in a system where coordinates are a prominent element. Maybe, a game engine makes the problem central and less trivial than in other software fields so that it requires an extra effort of attention, but imho this doesn't absolutely mean as a user I must search or imagine how a method was implemented

                Well, you can rationalize around it one way or another. The reality is - the approach you've taken has a potential to cause crashes. You can play on the safe side and instead of using find() iterate and call is_equal_approx(). Or don't do that and risk a buggy application. It's your call.

                Btw no need to manually calculate a distance between two points. Using Vector2::distance_to() results in much more readable code:

                total_pixel_length += p1.distance_to(p2)

                  xyz

                  Well, you can rationalize around it one way or another

                  It's not rationalization: basically, if you pretend I develop using your software, you must provide me with better documentation. This is in the interest of those who produce the software too, not only the engine users.

                  is_equal_approx()

                  I thought about that when you told me about the existence of is_equal_approx, but I didn't try it. I promised myself to ask you if it is more performant than find, but I completely forgot it.

                  p1.distance_to(p2)

                  I didn't know about it, I installed Godot 4 the same day I posted my first question here. Interestingly enough, Godot has a function that returns the total length of a curve and doesn't have a function that calculates the distance between two points in a curve.

                  Thanks for any help.

                  • xyz replied to this.

                    Catapult You should address your concerns to the developers. I'm just a user like yourself, trying to help you out with advice based on experience. Devs are not visiting this forum afaik.

                    Just don't forget that Godot is an open source project and as such it's always a work in progress.

                      xyz

                      trying to help you out with advice based on experience

                      And, in fact, I thank you for taking the time to answer to my questions, making your experience available to me.

                      Devs are not visiting this forum afaik

                      Not a smart move, imho.

                      is an open source project

                      It's open source, but for some reason it's getting bigger, and bigger open source projects need better docs.

                        Catapult Devs are not visiting this forum afaik

                        Not a smart move, imho.

                        Some of them have occasionally popped in here, but naturally most of their free time goes towards actually developing the engine, and there are more engine development focused channels of communication that they'd prioritize over the user forums. Those other channels are still open tho, and users can access them too. Just don't go spamming in there. If a meeting is taking place be patient - you can ask a question after the meeting is over.

                          Megalomaniak

                          don't go spamming in there

                          I must confess some of your advices arouses in me a certain wonderment :-)