Floating point precision in Approx

240 views
Skip to first unread message

Phil Nash

unread,
Jul 2, 2013, 1:50:07 PM7/2/13
to catch...@googlegroups.com

[Moved from Issue 183 on GitHub]

From Petter Strandmark:

See
https://github.com/philsquared/Catch/blob/master/include/internal/catch_approx.hpp#L22

Is there a reason why float is used instead of double? That gives about 5 digits, right? If it is correct, can it be made configurable?

Phil Nash

unread,
Jul 2, 2013, 2:00:21 PM7/2/13
to catch...@googlegroups.com
It's just the default for the epsilon value (note that it's also multiplied by 100). I've found that to be very useful for most cases. If you get too precise you tend to get a lot of noise.
If you know you need the precision it's trivial to set a specific epsilon value. e.g.:

     Approx1.23456789 ). epsilonstd::numeric_limits<double>::epsilon() );

If you're going to be doing that a lot you can define a reusable instance like this:

    Approx approx = Approx::custom().epsilon( 0.005 );


And then you can do, e.g.:

    REQUIRE( d == approx( 1.24 ) );

    REQUIRE( d != approx( 1.25 ) );


Martin Moene

unread,
Jul 2, 2013, 2:05:16 PM7/2/13
to catch...@googlegroups.com


On Tuesday, July 2, 2013 8:00:21 PM UTC+2, Phil Nash wrote:
...If you know you need the precision it's trivial to set a specific epsilon value. e.g.:

     Approx1.23456789 ). epsilonstd::numeric_limits<double>::epsilon() );

Except that the used code reads
explicit Approx ( double value )
        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),

cheers,
Martin

Phil Nash

unread,
Jul 2, 2013, 2:10:30 PM7/2/13
to catch...@googlegroups.com
One is what epsilon is constructed to by default - the other is explicitly setting it

Petter

unread,
Jul 3, 2013, 8:14:45 AM7/3/13
to catch...@googlegroups.com
Thanks for your responses. I was wondering whether using float in that one place was a typo. To me, it felt weird to use epsilon for float as a basis for double comparison.

Perhaps a more intuitive interface would be to allow the user to specify the number of digits that should match. If I remember correctly, this is the approach taken by Google.

Phil Nash

unread,
Sep 25, 2013, 1:35:30 PM9/25/13
to catch...@googlegroups.com
For more background on why Approx is implemented the way it is see this article:

(particularly the section: Comparing Floats).

It's by Richard Harris, a quant dev at on of the larger banks, as part of his series on floating point arithmetic, especially in a financial context.
If you look in the Approx source code you'll see that I also credit Richard with helping me design it. That article closely mirrors the conversation I had with him at the time.

Petter

unread,
Oct 14, 2013, 12:13:27 PM10/14/13
to catch...@googlegroups.com
Sorry, but after reading that article, I still don't understand why numeric_limits<float> was used instead of numeric_limits<double> for doubles.

Phil Nash

unread,
Oct 17, 2013, 12:43:49 PM10/17/13
to catch...@googlegroups.com
Sorry - I didn't meant to imply that it explains the float choice - but I think I explained that earlier in this thread - is it still unclear?

Victor Eijkhout

unread,
Jul 21, 2014, 12:57:14 PM7/21/14
to catch...@googlegroups.com
Eh, how does one use approx? I've just downloaded built 52 (the single include version), and I get:

unittest.cxx: In function 'void ____C_A_T_C_H____T_E_S_T____1907()':
unittest.cxx:1973:40: error: 'approx' was not declared in this scope
  CHECK( ydata[i] == approx( pow(3,s+1) ) );



Victor Eijkhout

unread,
Jul 21, 2014, 1:21:41 PM7/21/14
to catch...@googlegroups.com
Ah. Despite Phil's example, it's "Approx", not "approx".....

Victor.

Phil Nash

unread,
Jul 21, 2014, 1:29:11 PM7/21/14
to catch...@googlegroups.com
Hi Victor,

Yes Approx() is the type that Catch provides and which you would normally use. Where are you seeing me say "approx" (lowercase)? If there's an incorrect example I'll fix it.
If you mean my post in this thread from a year ago you'll see that was in the context of taking an instance of the Approx type with a specific epsilon value baked in:

  Approx approx = Approx::custom().epsilon0.005 );

(I could have called it anything - perhaps approx was a bad choice here).

In any event - glad you got it working.

Victor Eijkhout

unread,
Jul 21, 2014, 2:03:02 PM7/21/14
to catch...@googlegroups.com


On Tuesday, July 2, 2013 1:00:21 PM UTC-5, Phil Nash wrote:

And then you can do, e.g.:

    REQUIRE( d == approx( 1.24 ) );

    REQUIRE( d != approx( 1.25 ) );



I guess I misread this example.

Victor. 

Phil Nash

unread,
Jul 23, 2014, 2:14:00 AM7/23/14
to catch...@googlegroups.com

I guess I misread this example.

Thanks for confirming 
Reply all
Reply to author
Forward
0 new messages