boost-test, why is there no DOUBLES_EQUAL?

Hello, I am a regular user of the boost test library, having used CPPunit before. I miss the following macro: BOOST_CHECK_DOUBLES_EQUAL(first, second, absolute_tolerance); which would check whether "std::fabs(first-second) <= absolute_tolerance" is true. It seems the boost test library does not support it, and instead forces/encourages users to use BOOST_CHECK_CLOSE(first, second, percent_relative_tolerance); The above macro does not really make sense in my application, I really need to check for absolute tolerances, irrespectively of the magnitude of the numbers. CPPunit has this feature as DOUBLES_EQUAL. Would you consider adding this? Thanks, Sebastian

Sebastian Nowozin <nowozin <at> gmail.com> writes:
Hello,
I am a regular user of the boost test library, having used CPPunit before. I miss the following macro:
BOOST_CHECK_DOUBLES_EQUAL(first, second, absolute_tolerance);
Use BOOST_CHECK_SMALL. Gennadiy

Hello Grennadiy, On Tue, Mar 29, 2011 at 6:19 PM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
BOOST_CHECK_DOUBLES_EQUAL(first, second, absolute_tolerance); Use BOOST_CHECK_SMALL.
This does not do the job, as BOOST_CHECK_SMALL(std::fabs(first - second), 1.0e-3) will be about as useful as BOOST_CHECK(std::fabs(first - second) <= 1.0e-3) It is not useful because in case this check fails I do not get to see the original values of both 'first' and 'second', but only their difference. In my application, first and second are in the range of 0 to 1, but can in fact be quite close to zero. The qualitative test is correct if the absolute difference between first and second is small enough, irrespectively of the absolute value of first. Therefore, I fail to see why the boost test library provides only BOOST_CHECK_CLOSE and BOOST_CHECK_SMALL, but no analog to CPPUNIT_ASSERT_DOUBLES_EQUAL. Thanks, Sebastian

I've used and liked something like: BOOST_CHECK1(condition, p1) BOOST_CHECK2(condition, p1, p2) BOOST_CHECK3(condition, p1, p2, p3) with the meaning that if condition fails, then the first arguments (p1, p2, p3... depending on the number of arguments) are printed along with the condition that fails. In your case, you would write: BOOST_CHECK2(std::fabs(first - second) <= 1.0e-3, first, second) Now I'm not that familiar with BOOST_CHECK so I looked at the online documentation, and found the equivalent form: BOOST_CHECK_MESSAGE(std::fabs(first - second) <= 1.0e-3, "first:" << first << " second:" << second); Granted, the advantage of BOOST_CHECK_DOUBLE_EQUALS is that you do not have to repeat first and second. The use case is frequent enough that you might want the dedicated macro. The advantage of BOOST_CHECK_MESSAGE is that the message can be anything you want indicating some context, and it is the most general form you will want. The advantage of BOOST_CHECK[123] as I put it above is that p1, p2, p3... the message can be automatically constructed from the names and values of the variables (it is a macro after all, and it can use #p1 for creating the string "p1" so you don't have to do it). I've found it quite useful. -- Hervé Brönnimann On Apr 5, 2011, at 5:25 PM, Sebastian Nowozin wrote:
Hello Grennadiy,
On Tue, Mar 29, 2011 at 6:19 PM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
BOOST_CHECK_DOUBLES_EQUAL(first, second, absolute_tolerance); Use BOOST_CHECK_SMALL.
This does not do the job, as BOOST_CHECK_SMALL(std::fabs(first - second), 1.0e-3) will be about as useful as BOOST_CHECK(std::fabs(first - second) <= 1.0e-3)
It is not useful because in case this check fails I do not get to see the original values of both 'first' and 'second', but only their difference.
In my application, first and second are in the range of 0 to 1, but can in fact be quite close to zero. The qualitative test is correct if the absolute difference between first and second is small enough, irrespectively of the absolute value of first. Therefore, I fail to see why the boost test library provides only BOOST_CHECK_CLOSE and BOOST_CHECK_SMALL, but no analog to CPPUNIT_ASSERT_DOUBLES_EQUAL.
Thanks, Sebastian _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Sebastian Nowozin <nowozin <at> gmail.com> writes:
This does not do the job, as BOOST_CHECK_SMALL(std::fabs(first - second), 1.0e-3) will be about as useful as BOOST_CHECK(std::fabs(first - second) <= 1.0e-3)
It is not useful because in case this check fails I do not get to see the original values of both 'first' and 'second', but only their difference.
That's what you get for using suboptimal testing approach ;)
In my application, first and second are in the range of 0 to 1, but can in fact be quite close to zero.
You can still use ratio or percent based comparisons. They are more stable in general case and unless you have a very strong reason to prefer absolute comparison you should use relative one.
The qualitative test is correct if the absolute difference between first and second is small enough, irrespectively of the absolute value of first. Therefore, I fail to see why the boost test library provides only BOOST_CHECK_CLOSE and BOOST_CHECK_SMALL, but no analog to CPPUNIT_ASSERT_DOUBLES_EQUAL.
You are free to implement your own macro/comparison functor, but there are known good practices and Boost.Test punishes you a bit for not following them. Gennadiy

Gennadiy Rozental wrote:
Sebastian Nowozin <nowozin <at> gmail.com> writes:
This does not do the job, as BOOST_CHECK_SMALL(std::fabs(first - second), 1.0e-3) will be about as useful as BOOST_CHECK(std::fabs(first - second) <= 1.0e-3)
It is not useful because in case this check fails I do not get to see the original values of both 'first' and 'second', but only their difference.
That's what you get for using suboptimal testing approach ;)
Can you give an example or reference on a more optimal approach? Thanks, Jeff

Jeff Flinn <TriumphSprint2000 <at> hotmail.com> writes:
That's what you get for using suboptimal testing approach ;)
Can you give an example or reference on a more optimal approach?
My point was to nudge you toward percent or fraction based tolerance. Gennadiy

On Fri, Apr 8, 2011 at 7:01 AM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
Jeff Flinn <TriumphSprint2000 <at> hotmail.com> writes:
That's what you get for using suboptimal testing approach ;)
Can you give an example or reference on a more optimal approach?
My point was to nudge you toward percent or fraction based tolerance.
I believe the OP had already explained why relative tolerances were incorrect for his/her application. - Jeff

Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:
My point was to nudge you toward percent or fraction based tolerance. I believe the OP had already explained why relative tolerances were incorrect for his/her application.
I don't think so. He claimed he want absolute difference comparison without explaining why and relative is not applicable. My point is that *usually* one should prefer later. Gennadiy

On Fri, Apr 8, 2011 at 7:42 PM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:
My point was to nudge you toward percent or fraction based tolerance. I believe the OP had already explained why relative tolerances were incorrect for his/her application.
I don't think so. He claimed he want absolute difference comparison without explaining why and relative is not applicable.
Okay, there probably weren't enough details for a thorough justification, so my claim was indeed incorrect. I meant to say something along the lines of: I took the OP at his/her word that he/she had determined that absolute tolerances were correct to use and relative tolerances were incorrect. My point is that *usually* one should prefer later.
Perhaps, but that makes an implicit assumption about the "usual" application. In any case, usual or not, do we accept that absolute tolerances are sometimes preferable to relative tolerances? I would. If so, does it occur frequently enough to warrant the macro(s) (or a similar one(s)) that the OP suggested, similar to existing macros that check equality within relative tolerances? I don't know. But the only drawback I see with including such macros is a perhaps misplaced encouragement from the point of view of users to use the macros which determine equality within absolute tolerances; do we not trust users enough to determine on their own which tolerance type is appropriate for their application? - Jeff

Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:
My point is that *usually* one should prefer later.
Perhaps, but that makes an implicit assumption about the "usual" application.
I used word usually only because I prefer never or rarely use absolute statements.
In any case, usual or not, do we accept that absolute tolerances are sometimes preferable to relative tolerances? I would.
I would not. In my experience I've never seen a necessity for one (excluding the case where you want to check if something is small and in this case BOOST_CHECK_SMALL is strait to the point). I'd say that *usually* ;) desire to use absolute tolerance just indicates either lack of knowledge or lack of foresight. Even if you can come up with proper tolerance today, what will happen tomorrow when you change the notional or apply the same test in some other unrelated domain? With fraction based tolerance you can be much more comfortable that your test is still valid.
absolute tolerances; do we not trust users enough to determine on their own which tolerance type is appropriate for their application?
Yes. That one of the concerns on my part. In addition one you have two ways to do the same thing you'll have never ending stream of questions: what should one use? Gennadiy

On Sat, Apr 9, 2011 at 12:03 PM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:
In any case, usual or not, do we accept that absolute tolerances are sometimes preferable to relative tolerances? I would.
I would not. In my experience I've never seen a necessity for one (excluding the case where you want to check if something is small.
How about when doing calculations with money? /$

AMDG On 04/09/2011 08:28 AM, Henrik Sundberg wrote:
On Sat, Apr 9, 2011 at 12:03 PM, Gennadiy Rozental<rogeeff@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.<jeffrey.hellrung<at> gmail.com> writes:
In any case, usual or not, do we accept that absolute tolerances are sometimes preferable to relative tolerances? I would.
I would not. In my experience I've never seen a necessity for one (excluding the case where you want to check if something is small.
How about when doing calculations with money?
Dealing with money in floating point probably isn't the best idea to begin with. In Christ, Steven Watanabe

Gennadiy Rozental wrote:
Jeffrey Lee Hellrung, Jr. writes:
Perhaps, but that makes an implicit assumption about the "usual" application.
I used word usually only because I prefer never or rarely use absolute statements.
So you don't like absolute comparisons and rarely use absolute statements. Sounds very consistent to me.
In any case, usual or not, do we accept that absolute tolerances are sometimes preferable to relative tolerances? I would.
I would not.
OK, but do we accept that relative tolerances in the strict sense are sometimes not appropriate?
In my experience I've never seen a necessity for one (excluding the case where you want to check if something is small and in this case BOOST_CHECK_SMALL is strait to the point).
So you indeed accept that relative tolerances are sometimes not the way to go. However, the cases where I had to use BOOST_CHECK_SMALL in the past are not well characterized by saying that I wanted to check something is small. I had a vector as the result of some matrix problem, and wanted to check that the difference to the correct solution vector in the 2-norm was smaller than a tolerance times the condition number of the problem times the 2-norm of the input data.
I'd say that *usually* ;) desire to use absolute tolerance just indicates either lack of knowledge or lack of foresight. Even if you can come up with proper tolerance today, what will happen tomorrow when you change the notional or apply the same test in some other unrelated domain? With fraction based tolerance you can be much more comfortable that your test is still valid.
But BOOST_CHECK_CLOSE is often not the right way either. The problem is that BOOST_CHECK_CLOSE checks relative to the actual value, and not relative to the actual context. BOOST_CHECK_SMALL is fine for these cases, as far as the actual check is concerned. However, the resulting messages in case the check fails are suboptimal, as has been pointed out in this thread. But let me also point out that using BOOST_CHECK_DIFF_SMALL (absolute tolerance) on each component of a vector (similar to the use case described above) would produce much worse messages, because a single failed test would result in a flood of messages about failed checks. But using just BOOST_CHECK with an appropriate message seems to be a good solution.
absolute tolerances; do we not trust users enough to determine on their own which tolerance type is appropriate for their application?
Yes. That one of the concerns on my part.
Not very convincing, but also not completely wrong.
In addition one you have two ways to do the same thing you'll have never ending stream of questions: what should one use?
Yes, should I use BOOST_CHECK_SMALL as I currently do for my described use case, or BOOST_CHECK with an appropriate error message? Regards, Thomas

Hello, On Sat, Apr 9, 2011 at 3:42 AM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung <at> gmail.com> writes:
My point was to nudge you toward percent or fraction based tolerance. I believe the OP had already explained why relative tolerances were incorrect for his/her application.
I don't think so. He claimed he want absolute difference comparison without explaining why and relative is not applicable. My point is that *usually* one should prefer later.
The values I compare come from a Monte Carlo procedure, and are guaranteed to lie within a certain absolute tolerance. I compare the Monte Carlo results against exact values. Numerical stability is not an issue as these values are within the range zero to one. Therefore, you can safely assume that absolute deviation is the criteria I want to use, and is popularly used in the literature for this purpose (the so called total variation distance). I do not want to use relative comparisons, in particular because normalizing by a very small value such as 1.0e-10 can happen in that case. Sebastian

Sebastian Nowozin <nowozin <at> gmail.com> writes:
The values I compare come from a Monte Carlo procedure, and are guaranteed to lie within a certain absolute tolerance. I compare the Monte Carlo results against exact values. Numerical stability is not an issue as these values are within the range zero to one.
This is quite a big range. You can get values around 0.1 or around 1e-15. Will you be using the same tolerance in these cases?
Therefore, you can safely assume that absolute deviation is the criteria I want to use, and is popularly used in the literature for this purpose (the so called total variation distance). I do not want to use relative comparisons, in particular because normalizing by a very small value such as 1.0e-10 can happen in that case.
So? This will only make the comparison fair. 1e-10 and 2e-10 will differ by 1e-10, but the second value is twice as big. 0.9000000001 and 0.9000000002 differs only insignificantly. How can you catch this difference with absolute comparison? BOOST_CHECK_CLOSE on the other hand will work correctly. Gennadiy

On 4/5/2011 2:25 PM, Sebastian Nowozin wrote:
Hello Grennadiy,
On Tue, Mar 29, 2011 at 6:19 PM, Gennadiy Rozental<rogeeff@gmail.com> wrote:
BOOST_CHECK_DOUBLES_EQUAL(first, second, absolute_tolerance);
Use BOOST_CHECK_SMALL.
This does not do the job, as BOOST_CHECK_SMALL(std::fabs(first - second), 1.0e-3) will be about as useful as BOOST_CHECK(std::fabs(first - second)<= 1.0e-3)
It is not useful because in case this check fails I do not get to see the original values of both 'first' and 'second', but only their difference.
In my application, first and second are in the range of 0 to 1, but can in fact be quite close to zero. The qualitative test is correct if the absolute difference between first and second is small enough, irrespectively of the absolute value of first. Therefore, I fail to see why the boost test library provides only BOOST_CHECK_CLOSE and BOOST_CHECK_SMALL, but no analog to CPPUNIT_ASSERT_DOUBLES_EQUAL.
You can implement any check with a minor amount of code. Here, for example, is the test I have for making sure a quantity is within some tolerance of equality: template < typename Quantity > boost::test_tools::predicate_result compare_quantity(Quantity a, Quantity b, double tolerance) { double diff = abs(a.value() - b.value()); if ( diff > tolerance) { boost::test_tools::predicate_result res( false ); res.message() << "Quantities [" << a << "] and [" << b << "] do not fall within [" << tolerance << "]. Difference is [" << diff << "]"; return res; } return true; }
participants (9)
-
Gennadiy Rozental
-
Henrik Sundberg
-
Hervé Brönnimann
-
Jeff Flinn
-
Jeffrey Lee Hellrung, Jr.
-
Noah Roberts
-
Sebastian Nowozin
-
Steven Watanabe
-
Thomas Klimpel