Go Down

Topic: Problem comparing two float type numbers (Read 5073 times) previous topic - next topic

stuart0

#15
Jan 23, 2017, 03:23 pm Last Edit: Jan 23, 2017, 03:51 pm by stuart0
What alternative can I use if I need to have floating point numbers?
What Paul says above about picturing float values as being a bit fuzzy is a very good way to think about it.

For an example of why this (often) doesn't matter, say we had a float "x" and we wanted to choose different algorithms based on whether or not x was less than 1. Perhaps one algorithm was known to work better for x<1 and the other work better for x>1. In a case like this however, where x represents a continuous real world variable, it's a reasonable assumption that both algorithms are about the same when x=1. So realistically, it probably doesn't matter which algorithm we choose when x is very close to 1.0.

So in many cases like the above, the "fuzziness" of floats simply doesn't matter. And if it does matter, then it probably means that a float (at least of the precision you are using) is not appropriate for the problem at hand.

If you want some concrete examples of how we deal with this fuzziness in practice, the answer is that we usually use a "tolerance" constant that is appropriate for the precision we are using. For example:

#define toln 1e-6  // Thanks AWOL. ;)

In the following examples I'll assume we are comparing "float x" with 1.0.

For testing equality we would typically use:

if ( fabs(x-1.0) < toln ) ...

When testing inequality (for example less than) you could use either,

if (x < 1.0) ...
or
if (x <= 1.0)...

To be honest, it really shouldn't matter which of the above two that you use, at least if a float is truly appropriate for the problem at hand. In either case we don't really care what happens for values very close to 1.0. We simply accept that for calculations that would theoretically give 0.9999999 to 1.0000001, that it could go either way.

If for some reason we absolutely must have x=1 excluded, then use something like:

if (x + toln < 1.0) ...

If for some reason we absolutely must have x=1 included, then use something like:

if (x <= 1.0 + toln) ...

BTW. The choice for toln could depend upon just how many chained calculations (and how many opportunities there are for rounding errors) before you get to your comparison. But typically it would be somewhere about 1E-6 for single precision and somewhere about 1e-13 for double precision.


stuart0

#17
Jan 23, 2017, 03:44 pm Last Edit: Jan 23, 2017, 03:52 pm by stuart0
Oops
Yes, I'm from a very long time Pascal/Delphi background. I still make tons of little syntax errors like that every time I touch C/C++ :-* . Fortunately though, the compiler finds most of them for me pretty quickly. :)

gevorgparsyan

Thank you all for your comments and solutions.
stuart0, I guess the solution you offered is the simplest way to overcome this issue (of course taking into account the tolerance I will have in the values).


holmes4

Quote
stuart0, I guess the solution you offered is the simplest way to overcome this issue 
No use the code given in the link in reply #11

Mark

stuart0

#20
Feb 01, 2017, 04:10 pm Last Edit: Feb 01, 2017, 04:14 pm by stuart0
Thank you all for your comments and solutions.
stuart0, I guess the solution you offered is the simplest way to overcome this issue (of course taking into account the tolerance I will have in the values).
Yes. The main thing to take away is that most things are somewhat approximate with floats. So don't get too concerned about the distinction between "<" and "<=" (and similarly with ">" and ">=") when using the relational operators. And also make sure that you use some kind of tolerance when checking for (approximate) equality.

Re homles' comment above, yes please look at the link given for a more details. Notice that in my examples I only compared with unity (one), as that avoids any scaling problems with the tolerance. In practice this is usually achieved by comparing the ratio of two floats to unity instead of comparing the two directly.

The above works well on platforms with native floating point support (or at least native divide support). With MPU's that don't have native divide however, you are probably better off scaling the tolerance value in proportion with the values being compared, as that only requires multiply. See the above suggested link for more details.

Go Up