]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/test/include/boost/test/tools/floating_point_comparison.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / test / include / boost / test / tools / floating_point_comparison.hpp
1 // (C) Copyright Gennadiy Rozental 2001.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 // See http://www.boost.org/libs/test for the library home page.
7 //
8 //!@file
9 //!@brief algorithms for comparing floating point values
10 // ***************************************************************************
11
12 #ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
13 #define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
14
15 // Boost.Test
16 #include <boost/test/detail/global_typedef.hpp>
17 #include <boost/test/tools/assertion_result.hpp>
18
19 // Boost
20 #include <boost/limits.hpp> // for std::numeric_limits
21 #include <boost/static_assert.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/mpl/bool.hpp>
24 #include <boost/type_traits/is_floating_point.hpp>
25 #include <boost/type_traits/is_array.hpp>
26 #include <boost/type_traits/conditional.hpp>
27 #include <boost/utility/enable_if.hpp>
28
29 // STL
30 #include <iosfwd>
31
32 #include <boost/test/detail/suppress_warnings.hpp>
33
34 //____________________________________________________________________________//
35
36 namespace boost {
37 namespace math {
38 namespace fpc {
39
40 // ************************************************************************** //
41 // ************** fpc::tolerance_based ************** //
42 // ************************************************************************** //
43
44
45 //! @internal
46 //! Protects the instanciation of std::numeric_limits from non-supported types (eg. T=array)
47 template <typename T, bool enabled>
48 struct tolerance_based_delegate;
49
50 template <typename T>
51 struct tolerance_based_delegate<T, false> : mpl::false_ {};
52
53 template <typename T>
54 struct tolerance_based_delegate<T, true>
55 : mpl::bool_<
56 is_floating_point<T>::value ||
57 (!std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_exact)>
58 {};
59
60
61 /*!@brief Indicates if a type can be compared using a tolerance scheme
62 *
63 * This is a metafunction that should evaluate to @c mpl::true_ if the type
64 * @c T can be compared using a tolerance based method, typically for floating point
65 * types.
66 *
67 * This metafunction can be specialized further to declare user types that are
68 * floating point (eg. boost.multiprecision).
69 */
70 template <typename T>
71 struct tolerance_based : tolerance_based_delegate<T, !is_array<T>::value >::type {};
72
73 // ************************************************************************** //
74 // ************** fpc::strength ************** //
75 // ************************************************************************** //
76
77 //! Method for comparing floating point numbers
78 enum strength {
79 FPC_STRONG, //!< "Very close" - equation 2' in docs, the default
80 FPC_WEAK //!< "Close enough" - equation 3' in docs.
81 };
82
83
84 // ************************************************************************** //
85 // ************** tolerance presentation types ************** //
86 // ************************************************************************** //
87
88 template<typename FPT>
89 struct percent_tolerance_t {
90 explicit percent_tolerance_t( FPT v ) : m_value( v ) {}
91
92 FPT m_value;
93 };
94
95 //____________________________________________________________________________//
96
97 template<typename FPT>
98 inline std::ostream& operator<<( std::ostream& out, percent_tolerance_t<FPT> t )
99 {
100 return out << t.m_value;
101 }
102
103 //____________________________________________________________________________//
104
105 template<typename FPT>
106 inline percent_tolerance_t<FPT>
107 percent_tolerance( FPT v )
108 {
109 return percent_tolerance_t<FPT>( v );
110 }
111
112 //____________________________________________________________________________//
113
114 // ************************************************************************** //
115 // ************** details ************** //
116 // ************************************************************************** //
117
118 namespace fpc_detail {
119
120 // FPT is Floating-Point Type: float, double, long double or User-Defined.
121 template<typename FPT>
122 inline FPT
123 fpt_abs( FPT fpv )
124 {
125 return fpv < static_cast<FPT>(0) ? -fpv : fpv;
126 }
127
128 //____________________________________________________________________________//
129
130 template<typename FPT>
131 struct fpt_specialized_limits
132 {
133 static FPT min_value() { return (std::numeric_limits<FPT>::min)(); }
134 static FPT max_value() { return (std::numeric_limits<FPT>::max)(); }
135 };
136
137 template<typename FPT>
138 struct fpt_non_specialized_limits
139 {
140 static FPT min_value() { return static_cast<FPT>(0); }
141 static FPT max_value() { return static_cast<FPT>(1000000); } // for our purposes it doesn't really matter what value is returned here
142 };
143
144 template<typename FPT>
145 struct fpt_limits : boost::conditional<std::numeric_limits<FPT>::is_specialized,
146 fpt_specialized_limits<FPT>,
147 fpt_non_specialized_limits<FPT>
148 >::type
149 {};
150
151 //____________________________________________________________________________//
152
153 // both f1 and f2 are unsigned here
154 template<typename FPT>
155 inline FPT
156 safe_fpt_division( FPT f1, FPT f2 )
157 {
158 // Avoid overflow.
159 if( (f2 < static_cast<FPT>(1)) && (f1 > f2*fpt_limits<FPT>::max_value()) )
160 return fpt_limits<FPT>::max_value();
161
162 // Avoid underflow.
163 if( (f1 == static_cast<FPT>(0)) ||
164 ((f2 > static_cast<FPT>(1)) && (f1 < f2*fpt_limits<FPT>::min_value())) )
165 return static_cast<FPT>(0);
166
167 return f1/f2;
168 }
169
170 //____________________________________________________________________________//
171
172 template<typename FPT, typename ToleranceType>
173 inline FPT
174 fraction_tolerance( ToleranceType tolerance )
175 {
176 return static_cast<FPT>(tolerance);
177 }
178
179 //____________________________________________________________________________//
180
181 template<typename FPT2, typename FPT>
182 inline FPT2
183 fraction_tolerance( percent_tolerance_t<FPT> tolerance )
184 {
185 return FPT2(tolerance.m_value)*FPT2(0.01);
186 }
187
188 //____________________________________________________________________________//
189
190 } // namespace fpc_detail
191
192 // ************************************************************************** //
193 // ************** close_at_tolerance ************** //
194 // ************************************************************************** //
195
196
197 /*!@brief Predicate for comparing floating point numbers
198 *
199 * This predicate is used to compare floating point numbers. In addition the comparison produces maximum
200 * related differnce, which can be used to generate detailed error message
201 * The methods for comparing floating points are detailed in the documentation. The method is chosen
202 * by the @ref boost::math::fpc::strength given at construction.
203 */
204 template<typename FPT>
205 class close_at_tolerance {
206 public:
207 // Public typedefs
208 typedef bool result_type;
209
210 // Constructor
211 template<typename ToleranceType>
212 explicit close_at_tolerance( ToleranceType tolerance, fpc::strength fpc_strength = FPC_STRONG )
213 : m_fraction_tolerance( fpc_detail::fraction_tolerance<FPT>( tolerance ) )
214 , m_strength( fpc_strength )
215 , m_tested_rel_diff( 0 )
216 {
217 BOOST_ASSERT_MSG( m_fraction_tolerance >= FPT(0), "tolerance must not be negative!" ); // no reason for tolerance to be negative
218 }
219
220 // Access methods
221 //! Returns the tolerance
222 FPT fraction_tolerance() const { return m_fraction_tolerance; }
223
224 //! Returns the comparison method
225 fpc::strength strength() const { return m_strength; }
226
227 //! Returns the failing fraction
228 FPT tested_rel_diff() const { return m_tested_rel_diff; }
229
230 /*! Compares two floating point numbers a and b such that their "left" relative difference |a-b|/a and/or
231 * "right" relative difference |a-b|/b does not exceed specified relative (fraction) tolerance.
232 *
233 * @param[in] left first floating point number to be compared
234 * @param[in] right second floating point number to be compared
235 *
236 * What is reported by @c tested_rel_diff in case of failure depends on the comparison method:
237 * - for @c FPC_STRONG: the max of the two fractions
238 * - for @c FPC_WEAK: the min of the two fractions
239 * The rationale behind is to report the tolerance to set in order to make a test pass.
240 */
241 bool operator()( FPT left, FPT right ) const
242 {
243 FPT diff = fpc_detail::fpt_abs<FPT>( left - right );
244 FPT fraction_of_right = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( right ) );
245 FPT fraction_of_left = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( left ) );
246
247 FPT max_rel_diff = (std::max)( fraction_of_left, fraction_of_right );
248 FPT min_rel_diff = (std::min)( fraction_of_left, fraction_of_right );
249
250 m_tested_rel_diff = m_strength == FPC_STRONG ? max_rel_diff : min_rel_diff;
251
252 return m_tested_rel_diff <= m_fraction_tolerance;
253 }
254
255 private:
256 // Data members
257 FPT m_fraction_tolerance;
258 fpc::strength m_strength;
259 mutable FPT m_tested_rel_diff;
260 };
261
262 // ************************************************************************** //
263 // ************** small_with_tolerance ************** //
264 // ************************************************************************** //
265
266
267 /*!@brief Predicate for comparing floating point numbers against 0
268 *
269 * Serves the same purpose as boost::math::fpc::close_at_tolerance, but used when one
270 * of the operand is null.
271 */
272 template<typename FPT>
273 class small_with_tolerance {
274 public:
275 // Public typedefs
276 typedef bool result_type;
277
278 // Constructor
279 explicit small_with_tolerance( FPT tolerance ) // <= absolute tolerance
280 : m_tolerance( tolerance )
281 {
282 BOOST_ASSERT( m_tolerance >= FPT(0) ); // no reason for the tolerance to be negative
283 }
284
285 // Action method
286 bool operator()( FPT fpv ) const
287 {
288 return fpc::fpc_detail::fpt_abs( fpv ) <= m_tolerance;
289 }
290
291 private:
292 // Data members
293 FPT m_tolerance;
294 };
295
296 // ************************************************************************** //
297 // ************** is_small ************** //
298 // ************************************************************************** //
299
300 template<typename FPT>
301 inline bool
302 is_small( FPT fpv, FPT tolerance )
303 {
304 return small_with_tolerance<FPT>( tolerance )( fpv );
305 }
306
307 //____________________________________________________________________________//
308
309 } // namespace fpc
310 } // namespace math
311 } // namespace boost
312
313 #include <boost/test/detail/enable_warnings.hpp>
314
315 #endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER