[test] comparing floating point values

OK, here is an opportunity to get me clear on comparing floating point values. I've found a very simple example, that I can not get to work -- and understand... Say I have a class that saves and restores a class. In the class, I have a double, a float, and a long double. As a test, I set the "floating" values to std::numeric_limits< T >::min() and std::numeric_limits< T >::max(), and then save the values, restore them, and compare the restored values to the originals. Obviously, I can not use BOOST_CHECK_EQUAL(), but I am clueless as to how to use the macros for comparing floating point values. Is there anything in numeric_limits that I should use to base the percentage value? Here's a chance for someone to finally clear my understanding of how to compare floating point value... please ?!?!? Thanks!

Jody Hagins wrote:
Here's a chance for someone to finally clear my understanding of how to compare floating point value... please ?!?!?
:-) Let's say you want the tolerance to be N*eps where eps is the machine epsilon and N is you level of tolerance, then you can use either: BOOST_CHECK_CLOSE(a, b, N*100*numeric_limits<T>::epsilon()); // tolerance as a persent or: BOOST_CHECK_FRACTION(a, b, N*numeric_limits<T>::epsilon()); // tolerance as a fraction. There are still a couple of things that can get you: 1) This will fail if one of a and b is zero and the other isn't. Generally speeking you may want to treat all values below some threshold as "effectively zero", but what that threshold is depends on your use case. 2) This fails if a and b are both infinity, probably a Boost.Test bug. 3) This fails on MacOS X with T=long double, this is a problem with the excessively screwy long double on that platform: numeric_limits<long double>::epsilon() is defined to be the same as numeric_limits<double>::min(), which is very small indeed and much smaller than the usual "sane" value for epsilon of ldexp(1.0, 1-numeric_limits<long double>::digits). The latter expression is a viable replacement for if you care about MacOS X BTW. HTH, John.

On Tue, 15 May 2007 17:09:14 +0100 "John Maddock" <john@johnmaddock.co.uk> wrote: Thanks, John!!! I'm still not entirely sure I understand it, but it works ;-) I tested it with a std::stringstream... in and out... and after setting the stream precision large enough, the values in/out compared and the test passed. I then used the same comparisons for the values when I save/restore via my own code, and it works there too. Thanks, again!

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Jody Hagins Sent: 15 May 2007 18:22 To: boost@lists.boost.org Subject: Re: [boost] [test] comparing floating point values
On Tue, 15 May 2007 17:09:14 +0100 "John Maddock" <john@johnmaddock.co.uk> wrote:
Thanks, John!!!
I'm still not entirely sure I understand it, but it works ;-)
I tested it with a std::stringstream... in and out... and after setting the stream precision large enough, the values in/out compared and the test passed. I then used the same comparisons for the values when I save/restore via my own code, and it works there too.
A word of caution if you are using MSVC - there are some values for which your 'loopback', even with the sufficient number of decimal digits, does not work for a third of values (are 1 least significant bit off) in a narrow range, about 0.0001 - 0.0005. MS have declared this a 'feature': http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?Feedbac... In practice this is unlikely to bite you - but during testing it might, if you demand equality BOOST_CHECK_EQUAL rather than using a BOOST_CHECK_CLOSE_FRACTION() with a single epsilon sized tolerance. HTH too. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

On Wed, 16 May 2007 10:42:26 +0100 "Paul A Bristow" <pbristow@hetp.u-net.com> wrote:
In practice this is unlikely to bite you - but during testing it might, if you demand equality BOOST_CHECK_EQUAL rather than using a BOOST_CHECK_CLOSE_FRACTION() with a single epsilon sized tolerance.
Thanks, Paul. I don't use MSVC, but that piece of information actually helped me understand a little better what the test for "close" is doing.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Jody Hagins Sent: 16 May 2007 14:33 To: boost@lists.boost.org Subject: Re: [boost] [test] comparing floating point values
On Wed, 16 May 2007 10:42:26 +0100 "Paul A Bristow" <pbristow@hetp.u-net.com> wrote:
In practice this is unlikely to bite you - but during testing it might, if you demand equality BOOST_CHECK_EQUAL rather than using a BOOST_CHECK_CLOSE_FRACTION() with a single epsilon sized tolerance.
Thanks, Paul. I don't use MSVC,
So you will be pleased to know that I had reports that gcc didn't have this unwanted feature :-) Paul

"John Maddock" <john@johnmaddock.co.uk> wrote in message news:004001c7970b$6a2dcf50$ddff1b52@fuji...
Jody Hagins wrote:
Here's a chance for someone to finally clear my understanding of how to compare floating point value... please ?!?!?
:-)
Let's say you want the tolerance to be N*eps where eps is the machine epsilon and N is you level of tolerance, then you can use either:
BOOST_CHECK_CLOSE(a, b, N*100*numeric_limits<T>::epsilon()); // tolerance as a persent
or:
BOOST_CHECK_FRACTION(a, b, N*numeric_limits<T>::epsilon()); // tolerance as a fraction.
Yes. This looks correct with current interfaces.
There are still a couple of things that can get you:
1) This will fail if one of a and b is zero and the other isn't. Generally speeking you may want to treat all values below some threshold as "effectively zero", but what that threshold is depends on your use case.
2) This fails if a and b are both infinity, probably a Boost.Test bug.
You mean it should fail and it passes? Gennadiy

"John Maddock" <john@johnmaddock.co.uk> wrote in message news:00fd01c79790$2960c100$4d5a0252@fuji...
2) This fails if a and b are both infinity, probably a Boost.Test bug.
You mean it should fail and it passes?
No it failed, when I expected it to pass, however I don't have the test case to hand any more so maybe I misread the error messages?
Why do you expect two infinity values to be close with any tolerance? Gennadiy

Gennadiy Rozental wrote:
No it failed, when I expected it to pass, however I don't have the test case to hand any more so maybe I misread the error messages?
Why do you expect two infinity values to be close with any tolerance?
Interesting question: if the too values are the same, then I would have expected BOOST_CHECK_CLOSE to pass. But then we get into philisophical discussions about whether two infinities are really the same :-) John.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of John Maddock Sent: 16 May 2007 09:56 To: boost@lists.boost.org Subject: Re: [boost] [test] comparing floating point values
Gennadiy Rozental wrote:
No it failed, when I expected it to pass, however I don't have the test case to hand any more so maybe I misread the error messages?
Why do you expect two infinity values to be close with any tolerance?
Interesting question: if the too values are the same, then I would have expected BOOST_CHECK_CLOSE to pass. But then we get into philisophical discussions about whether two infinities are really the same :-)
Well we certainly don't want any philosophical discussions :-)) In BOOST_CHECK we are really comparing two bit patterns - both of which are std::numeric_limits<T>::infinity() and will presumably pass a BOOST_CHECK_EQUAL test, so I also would expect a BOOST_CHECK_CLOSE pass, whatever the tolerance. But most important is to try to agree and to document our conclusion? Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

"Paul A Bristow" <pbristow@hetp.u-net.com> wrote in message news:001601c7979f$b5c37bb0$0200a8c0@hetp7...
Why do you expect two infinity values to be close with any tolerance?
Interesting question: if the too values are the same, then I would have expected BOOST_CHECK_CLOSE to pass. But then we get into philisophical discussions about whether two infinities are really the same :-)
Well we certainly don't want any philosophical discussions :-))
In BOOST_CHECK we are really comparing two bit patterns - both of which are std::numeric_limits<T>::infinity() and will presumably
This is not exactly true in general. BOOST_CHECK uses operator==. BOOST_CHECK_CLOSE doesn't compare bit patterns either. It uses some advanced algorithm. So we may decide what is the desirable outcome.
pass a BOOST_CHECK_EQUAL test, so I also would expect a BOOST_CHECK_CLOSE pass, whatever the tolerance.
But most important is to try to agree and to document our conclusion?
Getting back to our FP we need to decide Does 0. == 0. NaN == NaN Inf == Inf. My guess is that curent algorithm produces false in all three cases. My vote would be to keep it this way. Gennadiy
Paul
--- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 5/18/07, Andrew Koenig <ark-mlist@att.net> wrote:
Does
The IEEE floating-point standard says:
0. == 0.
Yes.
NaN == NaN
No. NaN compares unordered with everything.
Inf == Inf.
Yes.
It's sad that Inf == Inf, because most infinities (an infinite number of them :-) are not equal. On the other hand, I'd like to be able to check for Inf (and NaN) so we need to compare them somehow. Tony

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Gennadiy Rozental Sent: 17 May 2007 19:09 To: boost@lists.boost.org Subject: Re: [boost] [test] comparing floating point values
"Paul A Bristow" <pbristow@hetp.u-net.com> wrote in message news:001601c7979f$b5c37bb0$0200a8c0@hetp7...
Why do you expect two infinity values to be close with any tolerance?
Interesting question: if the too values are the same, then I would have expected BOOST_CHECK_CLOSE to pass. But then we get into philisophical discussions about whether two infinities are really the same :-)
Well we certainly don't want any philosophical discussions :-))
This is not exactly true in general. BOOST_CHECK uses operator==. BOOST_CHECK_CLOSE doesn't compare bit patterns either. It uses some advanced algorithm. So we may decide what is the desirable outcome.
Agreed (and this is different from BOOST_CHECK_EQUAL, where being different from the IEEE spec and operator== would be confusing). BUT there IS a need to be able to see if you get NaN or infinity as a result - John and I have found this in checking the math toolkit. To do this we must have a Standard way of doing this - Standards writers please note the inordinate confusion caused by the previous lack of a Standard way of doing something very simple (but platform specific), having created a Standard way of creating infinity and NaNs in numeric_limits. Boost should soon have this when Johan Råde 's TR1 code comes up for review - and I trust acceptance. For BOOST_CHECK_CLOSE (and BOOST_CHECK_CLOSE_FRACTION) we (well Gennadiy at least ;-) can decide what the rules are. At present 1.34, my tests attached show that:
0. == 0. passes, whatever the tolerance (as long as it isn't NaN!).
NaN == NaN - fails
Inf == Inf - fails
My vote would be to keep it this way.
OK - but it needs documenting, perhaps with the attached example code. If you need (and our experience is that you do) to consider NaN and infinity then use the TR1 functions: template<class T> bool isfinite(T x); template<class T> bool isinf(T x); template<class T> bool isnan(T x); for example, if you expect a possible infinity result: perhaps from a dividebyzero caused by an underflow. double d = 1.23; double n = 0.; // force a divide by zero, double r = d / n; // expecting an infinity result. // cout << r << endl; // 1.#INF if (isfinite(r)) { BOOST_CHECK_CLOSE(r, 1., 0.000001); } else {// If not finite then we expect the result to be infinity. BOOST_CHECK(isinf(r)); } or mark a fail as expected. And similarly if you expect a NaN result. This extra code is a possible reason why BOOST_CHECK_CLOSE might do something smarter with non-finites. But this code is clear, if a hassle to write. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

Hi Jody, This may be a little off-topic but I believe it may help you better understand what these discrepancies are that you are seeing. Assume you have the following fractions: 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, 1/512, 1/1024, etc... You are then asked to select a group of these fractions such that their sum is 0.1, but you are told that there is a limit on the size of the group, for instance you can't use more than 6 fractions in the group (you can use any amount of them just no more than 6), Now the questions: 1. How close could you get to 0.1? 2. Could you represent 0.1 exactly? 3. From all the combinations that you could come up with, what would be the closest value to 0.1 you could come up with? Arash Partow __________________________________________________ Be one who knows what they don't know, Instead of being one who knows not what they don't know, Thinking they know everything about all things. http://www.partow.net Jody Hagins wrote:
OK, here is an opportunity to get me clear on comparing floating point values. I've found a very simple example, that I can not get to work -- and understand...
Say I have a class that saves and restores a class. In the class, I have a double, a float, and a long double. As a test, I set the "floating" values to std::numeric_limits< T >::min() and std::numeric_limits< T >::max(), and then save the values, restore them, and compare the restored values to the originals.
Obviously, I can not use BOOST_CHECK_EQUAL(), but I am clueless as to how to use the macros for comparing floating point values. Is there anything in numeric_limits that I should use to base the percentage value?
Here's a chance for someone to finally clear my understanding of how to compare floating point value... please ?!?!?
Thanks! _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Wed, 16 May 2007 19:20:50 +1000 Arash Partow <arash@partow.net> wrote:
Hi Jody,
This may be a little off-topic but I believe it may help you better understand what these discrepancies are that you are seeing. Assume you have the following fractions:
Thank, Arash. All input is beneficial. Aside from my recent rant about Boost.Test/1.34, I actually really like the features I get from Boost.Test (which is why I have put up with having to change our tests with every release). I just don't understand some of the documentation, so I've avoided those features... until I absolutely need them.
participants (7)
-
Andrew Koenig
-
Arash Partow
-
Gennadiy Rozental
-
Gottlob Frege
-
Jody Hagins
-
John Maddock
-
Paul A Bristow