approx.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "catch.h"
4 #include <limits>
5 #include <sstream>
6 #include <iomanip>
7 
8 
9 /*
10 
11 We need to compare floating point values, therefore we need an approximation
12 function, which Catch provides for us:
13  REQUIRE( performComputation() == Approx( 2.1 ));
14 (see https://github.com/catchorg/Catch2/blob/master/docs/assertions.md)
15 For example (with the default epsilon):
16  2.61007666588 ~= 2.61007662723
17 This may not be good enough for us...
18 
19 Three controls exist for the comparison:
20  - margin (absolute difference)
21  |a-b| <= margin
22  - scale - ignored for now; see below
23  - epsilon (relative difference)
24  |a-b| <= epsilon * |b|
25 
26 
27 Catch v1 vs v2
28 ----------------
29 
30 In v1, the formula for approx was:
31  |a-b| <= epsilon * (scale + max( |a|, |b| ))
32 With the default for scale being 1.
33 With v2, this changed to:
34  |a-b| <= margin || |a-b| <= epsilon * (scale + b )
35 (it's really slightly different, but the gist is the above)
36 The scale has changed to 0!
37 Note that it's now only relative to the "golden" number to which we're comparing!
38 
39 
40 Absolute vs relative comparisons
41 ----------------------------------
42 
43 Absolute and relative tolerances are tested as:
44  |a-b| <= MARGIN
45 and:
46  |a-b| <= EPSILON * max(|a|, |b|)
47 
48 The absolute tolerance test fails when x and y become large, and the relative
49 tolerance test fails when they become small. It is therefore best to combine
50 the two tests together in a single test.
51 
52 But this is always subject to context: generalizing here is convenient, that's all...
53 
54 
55 Approx to 0
56 -------------
57 
58 Because the scale is 0 in v2, and the margin defaults to 0, there is essentially no
59 approximate comparison to 0! We must use a margin if we want to do this.
60 
61 Which value to choose is a good question, though. Because most of our math is in
62 floats, we choose to use the float epsilon: any two numbers are deemed equal if their
63 difference is less than the smallest float number representable:
64 */
65 #if ! defined( __APPROX_MARGIN )
66 #define __APPROX_MARGIN std::numeric_limits<float>::epsilon()
67 #endif
68 template< typename F > struct __approx_margin {};
69 template<> struct __approx_margin< double > { static constexpr double value() { return __APPROX_MARGIN; } };
70 template<> struct __approx_margin< float > { static constexpr float value() { return __APPROX_MARGIN * 4; } };
71 template< typename F > F approx_margin( F ) { return __approx_margin< F >::value(); }
72 
73 /*
74 But note that for floats, this number is scaled up!
75 
76 
77 Epsilon
78 ---------
79 Approx sets its epsilon to:
80  std::numeric_limits<float>::epsilon()*100
81 This might be too big.
82 
83 Instead, we set the epsilon to the same as the margin, by default:
84 */
85 #if ! defined( __APPROX_EPSILON )
86 #define __APPROX_EPSILON __APPROX_MARGIN
87 #endif
88 template< typename F > struct __approx_epsilon {};
89 template<> struct __approx_epsilon< double > { static constexpr double value() { return __APPROX_EPSILON; } };
90 template<> struct __approx_epsilon< float > { static constexpr float value() { return __APPROX_EPSILON * 4; } };
91 template< typename F > F approx_epsilon( F ) { return __approx_epsilon< F >::value(); }
92 /*
93 Note that this is still way smaller than the default!
94 
95 
96 How?
97 ------
98 
99 We provide our own functions to do approximate comparison:
100  REQUIRE( performComputation() == approx( 2.1 ));
101 */
102 
103 // Custom version of Approx, ==> better replaced by matchers <== for more control,
104 // but provides LRS defaults that should closely (but not exactly) match them
105 template< typename F >
106 inline Catch::Approx approx( F f )
107 {
108  return Catch::Approx( f )
109  .margin( __approx_margin< F >::value() )
110  .epsilon( __approx_epsilon< F >::value() );
111 }
112 
113 /*
114 
115 Literals
116 ----------
117 
118 Note that Catch has literals that make the syntax nice:
119  using namespace Catch::literals;
120  REQUIRE( performComputation() == 2.1_a );
121 Because we have our own implementatin (and because it's more verbose) we do NOT want
122 to use the literal that Catch supplies.
123 
124 
125 Matchers
126 ----------
127 
128 The above are good, but if you want more control, matchers provide a customizable
129 comparison:
130  REQUIRE_THAT( performComputation(), approx_equals( 2.1 ));
131 Or, for more control:
132  REQUIRE_THAT( performComputation(), approx_abs( 2.1 ));
133  REQUIRE_THAT( performComputation(), approx_rel( 2.1 ));
134 Or, with the Catch matchers, even more:
135  REQUIRE_THAT( performComputation(), WithinAbs( 2.1, 0.1 )); // 2.0 -> 2.2
136  REQUIRE_THAT( performComputation(), WithinRel( 2.1, 0.05 )); // 5% from 2.1
137  REQUIRE_THAT( performComputation(), WithinUlps( 2.1, 2 )); // two epsilons from 2.1
138 These matchers are type-sensitive (float vs. double).
139 */
140 #define approx_abs(D) \
141  Catch::Matchers::WithinAbs( (D), approx_margin((D)) )
142 #define approx_rel(D) \
143  Catch::Matchers::WithinRel( (D), approx_epsilon((D)) )
144 #define approx_equals(D) \
145  ( approx_abs(D) || approx_rel(D) )
146 
147 
148 // Utility function to help debug precision errors:
149 // INFO( full_precision( d ) );
150 // REQUIRE( 0.0 == d );
151 template< class T >
153 {
154  std::ostringstream s;
155  s << std::setprecision( std::numeric_limits< T >::max_digits10 ) << d;
156  return s.str();
157 }
158 
__approx_margin< float >::value
static constexpr float value()
Definition: approx.h:70
string
GLsizei const GLchar *const * string
Definition: glad/glad/glad.h:2861
__APPROX_MARGIN
#define __APPROX_MARGIN
Definition: approx.h:66
__approx_margin< double >::value
static constexpr double value()
Definition: approx.h:69
__approx_margin
Definition: approx.h:68
catch.h
value
GLfloat value
Definition: glad/glad/glad.h:2099
f
GLdouble f
Definition: glad/glad/glad.h:1517
approx_margin
F approx_margin(F)
Definition: approx.h:71
approx_epsilon
F approx_epsilon(F)
Definition: approx.h:91
__approx_epsilon
Definition: approx.h:88
full_precision
std::string full_precision(T const d)
Definition: approx.h:152
__approx_epsilon< float >::value
static constexpr float value()
Definition: approx.h:90
approx
Catch::Approx approx(F f)
Definition: approx.h:106
__approx_epsilon< double >::value
static constexpr double value()
Definition: approx.h:89
s
GLdouble s
Definition: glad/glad/glad.h:2441
__APPROX_EPSILON
#define __APPROX_EPSILON
Definition: approx.h:86
rmse.d
d
Definition: rmse.py:171


librealsense2
Author(s): LibRealSense ROS Team
autogenerated on Fri Aug 2 2024 08:30:00