Actually, there are vague mentions of the problem in the documentation, but very nebulous and the proposed solution is not very elegant:

Note: Due to floating-point precision errors, consider using is_equal_approx instead, which is more reliable.

  • xyz replied to this.

    Tomcat It's closely related but it's not exactly the problem you've experienced here. People generally heard about the caveat of "never comparing two floats using the operator ==". But your "bug" is a bit more insidious because your code never actually uses operator == to compare floats.

    The confusing thing about this is the fact that some rational numbers that have finite numbers of decimals in base 10 representation, may have infinite number of decimals in base 2 representation and thus cannot be stored in the binary form without some small error. And this error will differ depending on the number of bits used to store the number. It's similar to how e.g. 1/3 cannot be accurately stored in finite number of decimals in base 10 representation but in base 3 representation (trenary system) it can be fully stored with just one decimal (1/3 is exactly 0.1 when written in trenary system)

    How risky is this code:

    @export var high_min: = 0.0
    @export var high_max: = 1.57
    
    var high: = Vector2(high_min, high_max)

    it is for separate input of vector components values. Then high.x and high.y will be compared component by component.

    • xyz replied to this.

      Tomcat It on depends what you do with it afterwards. If you continue to deal only with float32 numbers i.e. vector components, you should be fine. But in practice, it's really easy to make an oversight and assign a vector component to some plain float. So that's the situation you need to watch out for. It may not be a problem in most calculations, but as you've seen in your example, there are cases in which it can break your code.

      Of course if you do equality checks using operator ==, you still may have problems even if all numbers are float32. So always use is_equal_approx() instead of == for equality checks.

      But once you know this, all such gotchas can be easily detected and debugged by printing out your values every step of the way.

        xyz If you continue to deal only with float32 numbers i.e. vector components

        Yeah, that's right.

        So that's the situation you need to watch out for.

        Unfortunately, as I realized, programming is generally a field where you have to be extremely careful. ๐Ÿ˜พ

        • xyz replied to this.

          Tomcat Unfortunately, as I realized, programming is generally a field where you have to be extremely careful. ๐Ÿ˜พ

          Yeah, it's not for the easily distracted ๐Ÿ™‚

          Tomcat Oh and just as a side node, if you redo your logic to eliminate this redundant check:

          if tilt.position.y >= high_min and tilt.position.y <= high_max:

          mixing 32 and 64 bit floats wouldn't matter.
          So you can simply do:

          tilt.position.y += event.relative.y * SENSITIVITY
          if tilt.position.y < high_min:
          	tilt.position.y = high_min
          if tilt.position.y > high_max:
          	tilt.position.y = high_max

          Which is exactly the same thing the clamp() does.

            xyz if you redo your logic to eliminate this redundant check:

            Yeah, I try to shorten the code as much as possible.

            Which is exactly the same thing the clamp() does.

            Using clamp() is of course shorter and more elegant, but now I wanted to understand the logic of setting and using vector components. And I think I almost understand it (or so it seems to me) with your help.

            xyz than the most common issue of precision loss when converting between decimal and binary.

            Just curious, do ternary logic computers have the same problem?

            • xyz replied to this.

              Tomcat I don't think such computers exist in practice. Watch out not to confuse trinary logic with trinary numeral system. Those are two different concepts. I was talking about the latter. But this is a "problem" of the floating point representation in general, regardless of the base. Floating point representation doesn't necessarily need to be binary. Theoretically, it can have any base. We just commonly use base 2 in computers because computers internally store data in binary form.

                xyz Watch out not to confuse trinary logic with trinary numeral system.

                That's about what I was asking:

                Setun (Russian: ะกะตั‚ัƒะฝัŒ) was a computer developed in 1958 at Moscow State University. It was built under the leadership of Sergei Sobolev and Nikolay Brusentsov. It was the most modern ternary computer, using the balanced ternary numeral system and three-valued ternary logic instead of the two-valued binary logic prevalent in other computers.