 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Matthias Hofmann Guest
|
Posted: Fri Feb 24, 2006 3:06 am Post subject: Comparing floating point values for equality |
|
|
Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++. I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Klomanager
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Fri Feb 24, 2006 10:06 am Post subject: Re: Comparing floating point values for equality |
|
|
Matthias Hofmann wrote:
| Quote: | Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++. I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
|
Well, I tried your idea. Here's my program:
#include <iostream>
int main()
{
float f1 = 0.1f;
f1 *= 9;
float f2 = 0.9f;
if (f1 == f2)
std::cout << f1 << " equals " << f2;
else
std::cout << f1 << " does not equal " << f2;
std::cout << std::endl;
}
and here's its output:
0.9 does not equal 0.9
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Guest
|
Posted: Fri Feb 24, 2006 11:06 am Post subject: Re: Comparing floating point values for equality |
|
|
Matthias Hofmann wrote:
| Quote: | Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++.
|
Not just C++, any language has the same problems. It's a property of
floating poitn numbers.
| Quote: | I recall that there are cases when such a comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all.
|
Definitely, else equal(1.0, 1.0/3.0*3.0) could be false.
| Quote: | Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
|
That will likely fail with the numbers suggested.
The advantage of <0.1 is that it "works" around 0. It won't work for
very big
numbers. Are 0.01 and 0.02 equal? Are 1.00 million and 1.00001 million
equal?
There are no quick answers here. One alternative is to check if
abs((f1/f2)-1) < 0.01.
That does work independent of scale, but fails close to 0.
HTH,
Michiel Salters
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Fri Feb 24, 2006 11:06 am Post subject: Re: Comparing floating point values for equality |
|
|
Matthias Hofmann wrote:
| Quote: | Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++. I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
|
use a compare function which passes in a (+/-) tolerance range in which
the two values can be said to be equal. Note also judicious use of abs.
(From experience I have found that the tolerance argument can be
negative). The function can also be used instead of comparison
operators of course
regards
Andy Little
/*
if( a ~=~ b ) return 0;
if( a > b ) return 1;
if( a < b ) return -1;
*/
#include <cmath>
template <typename Float>
int compare(Float const & a, Float const & b, Float const & tolerance)
{
Float difference = a-b;
if ( std::abs(difference) < std::abs(tolerance) ){
return 0;
}
else{
if (difference > 0){
return 1;
}
else {
return -1;
}
}
}
#include <iostream>
int main()
{
std::cout.precision(9);
double a = 1;
double b = 1.0000001;
double tolerance1 = 1e-6;
double tolerance2 = 1e-8f;
std::cout << "in range tolerance1? "
<< std::boolalpha << (compare(a,b,tolerance1) == 0 ) << '\n';
std::cout << "in range tolerance2? "
<< std::boolalpha << (compare(a,b,tolerance2) == 0 ) << '\n';
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Niek Sanders Guest
|
Posted: Fri Feb 24, 2006 11:06 am Post subject: Re: Comparing floating point values for equality |
|
|
| Quote: | I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
|
The appropriate constant wiggle factor (sometimes called epsilon)
varies depending on your algorithms. If you make the value too large
and you massively reduce the numerical resolution (e=0.1 means that
1.00 == 1.09). Make it too small and you will get false mismatches.
For my code (a raytracer), I tend to use 1E-6 as the wiggle when
dealing with 32-bit floats. A typical item of comparison would be a
polygon vertex coordinate versus a point generated by a ray
intersection algorithm. Look at the sources of numerical noise: the
view ray must be computed, the view ray goes through several affine
transforms (platform -> instrument mount -> global to local) followed
by whatever numerical precision is lost throw the projection from the
intersect algorithm.
So in short, the correct value for the wiggle depends on the accuracy
of the algorithms your floats pass through. If an analytic solution
would indicate the two values equal, then the wiggle should be large
enough for the numeric solution to do the same.
| Quote: | Maybe I can simply compare the floating point values like this:
float f1, f2;
bool equal = (f1 == f2);
|
This is almost certainly not what you want. For instance, the
following code returns mismatch on my G4 mac using gcc:
double lhs = 4.44;
double rhs = 4440000.0 * 1E-6;
std::cout << (lhs==rhs? "match" : "mismatch") << std::endl;
Cheers,
Niek Sanders
http://www.cis.rit.edu/~njs8030/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Fri Feb 24, 2006 11:06 am Post subject: Re: Comparing floating point values for equality |
|
|
Matthias Hofmann wrote:
| Quote: | I need to compare floating point values for equality, but I
remember that this can be a tricky thing in C++.
|
There's nothing tricky about it, neither in C++ nor in any other
language. What's tricky is knowing when comparison for equality
is appropriate -- in C++ and in every other programming
language. Machine floating point values are NOT real numbers,
and do not obey the rules of real number arithmetic.
| Quote: | I recall that there are cases when such a comparison should be
done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
|
That's rarely an appropriate solution -- according to your
routine, 0.09 is equal to 0.0, and I cannot imagine a context
where that would be acceptable.
There are cases where "close enough" can be treated as equal,
but the definition of close enough will depend very much on what
you are trying to do. Note, however, that when using "close
enough", a equals b and b equals c does not mean that a equals
c; close enough is not an equivalence relationship.
| Quote: | I am not sure which constant to use (0.1 seems a bit too much)
and whether this method is necessary at all. Maybe I can
simply compare the floating point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
|
Not in the scope of a newsgroup article. Try searching for
"What All Computer Programmers Should Know about Floating Point
Arithmetic" -- there are numerous copies on the net, and it
should be required reading before using float or double.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Dietmar Kuehl Guest
|
Posted: Fri Feb 24, 2006 12:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
Matthias Hofmann wrote:
| Quote: | I need to compare floating point values for equality,
|
In general, you will almost certainly not get the desired results.
| Quote: | but I remember that this can be a tricky thing in C++.
|
This is not a tricky thing in C++: this is a tricky thing in all
programming languages!
| Quote: | I recall that there are cases when such
a comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
|
Yes, this is about it. The exact details on the chosen epsilon
depend on your application but effectively, the above approach
is the only viable one.
| Quote: | I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
|
No, this does not really work out except in very few cases: if
the values of 'f1' and 'f2' are effectively just copies of the
same original value and never changed their type, this should
be safe. However, as soon as some computations are involved,
you are most likely ending up with different values. The issue
about comparison between floating point values is that the
numeric operations are not closed over the set of possible
values. That is, 'x @ y' (where '@' is any suitable operation)
may yield a value which cannot be represented as a floating
point value. That is, when determining the result of an
expression involving floating point types, some rounding occurs.
The exact details of rounding are also not that straight forward
as the computation may actually be performed using a different
representation for the floating point types. For example, the
processor normally computes with a higher precision than 'float'
and only the result of multiple operations may be rounded to the
actual representation.
The net effect is that floating point values normally differ at
least in a few bits. Even if these are that insignificant that
printing the values shows identical values (with "normal"
precision in printing), the comparison will yield 'false'. To
effectively compare floating point values for equality, you need
to determine a suitable maximum difference and check whether the
distance between your two values does not exceed this difference.
The maximum difference is effectively the accumulated imprecision
over the entire computation. What this value is, depends on the
actual application. Also, I seem to remember that sometimes a
relative difference is used.
--
<mailto:dietmar_kuehl (AT) yahoo (DOT) com> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Fri Feb 24, 2006 3:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
kwikius wrote:
| Quote: | Matthias Hofmann wrote:
Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++. I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
use a compare function which passes in a (+/-) tolerance range in which
the two values can be said to be equal. Note also judicious use of abs.
(From experience I have found that the tolerance argument can be
negative). The function can also be used instead of comparison
operators of course
|
Just to make the function slightly more robust:
#include <cmath>
template <typename Float>
int compare(Float const & a,
Float const & b,
Float const & tolerance)
{
Float difference = a-b;
if ( (difference == Float(0) )
|| (std::abs(difference) <= std::abs(tolerance)) ){
return 0;
}
else{
if (difference > 0){
return 1;
}
else {
return -1;
}
}
}
regards
Andy Little
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Fri Feb 24, 2006 3:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
Many thanks to all of you for this useful information! I think I should
mention that in my algorithm, I am actually dealing with percentages, so the
floating point values will range between 0 and 1. Here's a piece of code
that demonstrates how they are retrieved:
double a, b, c;
double x, y, z;
....
double d1 = a / ( a + b + c );
double d2 = x / ( x + y + z );
if ( equal( d1, d2 ) )
{
// Handle equality.
}
As you can see, I am planning to use 'double' instead of 'float' because the
former has a larger mantissa, and the latter might not be able to handle the
ranges needed for a, b, c and x, y, z. Given that, what epsilon should I
choose in order to get "good" equality results? I am working with Microsoft
Visual C++ on 32 bit Windows, in case that information helps.
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Klomanager
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Fri Feb 24, 2006 5:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
Greg Herlihy wrote:
| Quote: |
and here's its output:
0.9 does not equal 0.9
|
Your point being, of course, that roundoff during conversion for output
loses precision, so the two (different) values are displayed incorrectly.
The same thing occurs with integer math, except that we're used to it:
int i = 1;
int j = i / 3;
int k = j * 3;
Now, k isn't equal to i, but nobody says "don't use == to compare
integer values."
Floating-point math has the same kind of limitations: representations of
values have a limited precision, so you can lose information when longer
results get cut short to fit in the data type. So you either tolerate
the roundoff error or you code around it. It's not as straightforward
with floating-point types as it is with integral types, but the
principal is the same.
--
Pete Becker
Roundhouse Consulting, Ltd.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Daniel T. Guest
|
Posted: Fri Feb 24, 2006 5:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
In article <43fe23b9$0$13607$9b4e6d93 (AT) newsread2 (DOT) arcor-online.net>,
"Matthias Hofmann" <hofmann@anvil-soft.com> wrote:
| Quote: | Hello!
I need to compare floating point values for equality, but I remember that
this can be a tricky thing in C++. I recall that there are cases when such a
comparison should be done as follows:
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
I am not sure which constant to use (0.1 seems a bit too much) and whether
this method is necessary at all. Maybe I can simply compare the floating
point values like this:
float f1, f2;
bool equal = (f1 == f2);
Can anyone clarify this for me?
|
This is an FAQ, including the formula...
<http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17>
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Fri Feb 24, 2006 5:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
kanze wrote:
| Quote: |
bool equal( float f1, float f2 )
{
return std::fabs( f1 - f2 ) < 0.1;
}
That's rarely an appropriate solution -- according to your
routine, 0.09 is equal to 0.0, and I cannot imagine a context
where that would be acceptable.
|
Ignoring the other problems that arise from this kind of "approximately
equal" predicate, the tolerance needs to be determined by the magnitude
of the numbers involved in the problem.
For astronomers measuring distances in miles the difference between 0.09
and 0.00 (not 0.0, which only has two digits precision, while 0.00 has
three) is lost in the measurement noise. That is, if the values being
compared are accurate to the nearest million miles or so <g>,
differences of .09 just don't matter. 1,000,000,000.09 and
1,000,000,000.00 are the same value, and anyone who insisted they are
different would get a long lecture about false precision. (I wrote about
this physicist's perspective on floating point errors in a CUJ column
several years ago, available at www.petebecker.com/js200007.html).
--
Pete Becker
Roundhouse Consulting, Ltd.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Fri Feb 24, 2006 5:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
Niek Sanders wrote:
| Quote: |
For my code (a raytracer), I tend to use 1E-6 as the wiggle when
dealing with 32-bit floats.
|
Replacing == with this form of "approximately equal" removes the obvious
(but valid) incongruities of ==, but it replaces them with its own set
of quirks.
First, using a fixed value means that your code doesn't scale. If you
change your measurement units from inches to feet the actual numbers
become smaller, but the tolerance stays the same, so points that were
different are now considered equal. In any particular application that
may be appropriate, but as a general solution, the size of the allowable
difference has to depend on the size of the values being compared.
Second, this approach has the rather frightening property that it isn't
transitive. There are lots of values for which equal(a,b) is true, and
equal(b,c) is true, but equal(a,c) is false. This can lead to mysterious
results, including crashes when an algorithm requires transitivity.
--
Pete Becker
Roundhouse Consulting, Ltd.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Fri Feb 24, 2006 6:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
In article <43fefd38$0$13609$9b4e6d93 (AT) newsread2 (DOT) arcor-online.net>,
Matthias Hofmann <hofmann@anvil-soft.com> writes
| Quote: | Many thanks to all of you for this useful information! I think I should
mention that in my algorithm, I am actually dealing with percentages, so the
floating point values will range between 0 and 1. Here's a piece of code
that demonstrates how they are retrieved:
double a, b, c;
double x, y, z;
...
double d1 = a / ( a + b + c );
double d2 = x / ( x + y + z );
if ( equal( d1, d2 ) )
{
// Handle equality.
As you can see, I am planning to use 'double' instead of 'float' because the
former has a larger mantissa, and the latter might not be able to handle the
ranges needed for a, b, c and x, y, z. Given that, what epsilon should I
choose in order to get "good" equality results? I am working with Microsoft
Visual C++ on 32 bit Windows, in case that information helps.
|
Choosing to use fabs(d1 -d2)< epsilon requires knowledge of the expected
size of d1. Consider:
fabs(1 - d1/d2) < epsilon;
Now choose epsilon to meet your needs. Only you know how close to
equality is close enough.
Note that you should always use double unless you have very precise
reasons for needing to use float. I get tired of books for novices that
insist on using float because that rarely saves anything of consequence.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Sat Feb 25, 2006 12:06 pm Post subject: Re: Comparing floating point values for equality |
|
|
Pete Becker wrote:
| Quote: | Greg Herlihy wrote:
and here's its output:
0.9 does not equal 0.9
Your point being, of course, that roundoff during conversion for output
loses precision, so the two (different) values are displayed incorrectly.
|
No, the point is that floating point values, unlike integer
representations, do not always represent exact values exactly. 1
multiplied by 9 equals 9 exactly for integer values, but 0.1 times 9 is
not certain to equal 0.9 exactly when the values are represented by
floating point types. So if the original poster believes that 0.1 times
9 should equal 0.9 exactly, then the suggested test for equality
between the floating point result and the expected floating point
value, will not in fact be able to fulfill that expectation.
| Quote: | The same thing occurs with integer math, except that we're used to it:
int i = 1;
int j = i / 3;
int k = j * 3;
Now, k isn't equal to i, but nobody says "don't use == to compare
integer values."
|
Integer multiplication is not the inverse of integer division, so there
should be no expectation that k would be equal to i after performing
those two operations. Instead we know that k will equal 0 exactly and,
more importantly, comparing k with 0 will confirm that equality since k
is an integer value.
| Quote: | Floating-point math has the same kind of limitations: representations of
values have a limited precision, so you can lose information when longer
results get cut short to fit in the data type. So you either tolerate
the roundoff error or you code around it. It's not as straightforward
with floating-point types as it is with integral types, but the
principal is the same.
|
There is a sharp difference between fixed and floating point
representations. The difference is not merely one of scale. The
difference is that one is exact, and the other is not. 1 divided by 3
using integer division produces an exact result: 0. The 0 valued result
is not an approximation of the actual value, instead both the expected
result from the operation and its represented value are 0. This quality
of exactness - in which the represented value is always an exact value
- is not guaranteed with floating point operations, even when the
values are exactly specified and the expected value of the operation is
exact, as my program demonstrated. For those used to the exactness of
integer arithmatic, the inexactness of floating point values is often
surprising.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|