2

I know that due to precision errors, a float varibale should be checked to equal a value always with some tolerance. But what's is that even the case if I manually set the float variable to 0.0f?

For example there is a function returning a distance.

float distance()
{
    float value;
    if(/* ... */)
    {
        // ...
        return value;
    }
    else return 0.0f;
}

Can I cast the result to bool safely?

if(distance())
{
   // ...
}
danijar
  • 32,406
  • 45
  • 166
  • 297
  • 2
    That would be entirely confusing to a future developer.. why not set a constant called `ZERO_DISTANCE` and just say, `if(distance() != ZERO_DISTANCE)`? –  May 10 '13 at 12:54
  • @0A0D i do not think that it is much better style to compare float values against defines or consts. Also it is bad style to test `if( /* float expression */)` why not simply test for ìf( abs(value) <= epsilon)` – vlad_tepesch May 10 '13 at 12:58
  • When I return `0.0f` then that really means a distance of zero. Therefore it won't be confusing. The question is if I can rely on the result to be cast to `false` later. – danijar May 10 '13 at 12:59
  • @0A0D no. thou shall not test equality on floats. – Elazar May 10 '13 at 12:59
  • 7
    @Elazar Rubbish. Thou can perfectly well test for equality on floats if that is the right thing to do. – David Heffernan May 10 '13 at 13:00
  • 2
    @vlad_tepesch: Because the OP isn't testing if its less than or equal to an epsilon? You can have a negative distance too, so `abs` isn't needed always. At least in this case, he is testing if its __zero__, nothing else. –  May 10 '13 at 13:02
  • 1
    Never check a float against 0.0... except when you want to know if the value of that float is 0.0. – Daniel Daranas May 10 '13 at 13:02
  • 1
    There are no casts in this code. The question is about a **conversion**. A **cast** is something you write in your code that tells the compiler to do a **conversion**. – Pete Becker May 10 '13 at 13:32
  • 1
    And, no, it's **not** automatically a good thing to test floating-point values for "nearly equal". If you don't understand what's happening in the calculation that produced a value, fudging a test won't fix it. – Pete Becker May 10 '13 at 13:33
  • @PeteBecker: Relational operators on fuzzy quantities fundamentally have four states: X is definitely bigger, Y is definitely bigger, they're two close to tell, or they're not comparable (e.g. one or both is NaN). Sometimes it's better to detect things that are too close to tell as equal, but sometimes it's better to maintain a strictly-consistent ranking and promise that the sets of things that compare equal form equivalence relations. – supercat May 13 '13 at 17:11
  • @supercat - that is one way to design them, but I have yet to see an answer or comment suggesting that approach to beginners who aren't in control of their floating-point calculations; it's always "see if they're nearly the same because, after all, you never really know..." – Pete Becker May 13 '13 at 17:18
  • @PeteBecker: Instead of saying "relational operators" I should have said "relational comparisons". From a language-design perspective, it's probably better to have the *operators* impose a ranking which is consistent and whose definition of "equality" forms an equivalence relation, than have them do anything else, but code which needs to compare things will likely need to recognize the fuzzy nature of comparisons. – supercat May 13 '13 at 17:22

5 Answers5

10

When you write:

if(distance())

you are checking whether the float is zero or not.

Your code is equivalent to

if(distance() != 0)

This is perfectly safe to do, and only you can determine whether or not it has the meaning that you require.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
3

If you have an exact value that you expect, there's absolutely no reason not to compare against that exact value. It's only when you perform a computation and get an inexact result that it's unsafe to compare against an exact value. And you generally want to assume that any floating point computation will give an inexact result.

In your case, you're returning a constant, so it's safe to compare to a constant.

Another time you'd want to compare against an exact value is to avoid singularities. For example, x == 0.0 ? 1.0 : sin(x)/x.

Gabe
  • 84,912
  • 12
  • 139
  • 238
2

Basically, you're asking if you can assume that the following line won't fire.

assert(0.0f); 

Yes. You can assume that.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
2

Technically, yes; 0.0f is representable by the IEEE 754 standard. However, the question is that will it be always zero, when you expect it to be and not the next floating point number.

I wouldn't do it, though.

Oszkar
  • 687
  • 1
  • 5
  • 20
1

You're correct to worry about floating-point inaccuracy, but you're also correct to suppose that it isn't a problem in this case.

The likelihood of your computer storing 0.0f as anything other than precisely zero is astronomical, and a conversion of precisely floating-point zero to boolean is well-defined.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055