fix doc example typo
[boost.git] / boost / test / floating_point_comparison.hpp
blob8ec7eb4105b3763e42001dcb977ab90acb356e86
1 // (C) Copyright Gennadiy Rozental 2001-2008.
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)
6 // See http://www.boost.org/libs/test for the library home page.
7 //
8 // File : $RCSfile$
9 //
10 // Version : $Revision$
12 // Description : defines algoirthms for comparing 2 floating point values
13 // ***************************************************************************
15 #ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
16 #define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
18 // Boost.Test
19 #include <boost/test/detail/global_typedef.hpp>
20 #include <boost/test/utils/class_properties.hpp>
21 #include <boost/test/predicate_result.hpp>
23 // Boost
24 #include <boost/limits.hpp> // for std::numeric_limits
25 #include <boost/numeric/conversion/conversion_traits.hpp> // for numeric::conversion_traits
26 #include <boost/static_assert.hpp>
28 #include <boost/test/detail/suppress_warnings.hpp>
30 //____________________________________________________________________________//
32 namespace boost {
34 namespace test_tools {
36 using unit_test::readonly_property;
38 // ************************************************************************** //
39 // ************** floating_point_comparison_type ************** //
40 // ************************************************************************** //
42 enum floating_point_comparison_type {
43 FPC_STRONG, // "Very close" - equation 1' in docs, the default
44 FPC_WEAK // "Close enough" - equation 2' in docs.
48 // ************************************************************************** //
49 // ************** details ************** //
50 // ************************************************************************** //
52 namespace tt_detail {
54 // FPT is Floating-Point Type: float, double, long double or User-Defined.
55 template<typename FPT>
56 inline FPT
57 fpt_abs( FPT arg )
59 return arg < static_cast<FPT>(0) ? -arg : arg;
62 //____________________________________________________________________________//
64 template<typename FPT>
65 struct fpt_limits {
66 static FPT min_value()
68 return std::numeric_limits<FPT>::is_specialized
69 ? (std::numeric_limits<FPT>::min)()
70 : 0;
72 static FPT max_value()
74 return std::numeric_limits<FPT>::is_specialized
75 ? (std::numeric_limits<FPT>::max)()
76 : static_cast<FPT>(1000000); // for the our purpuses it doesn't really matter what value is returned here
80 //____________________________________________________________________________//
82 // both f1 and f2 are unsigned here
83 template<typename FPT>
84 inline FPT
85 safe_fpt_division( FPT f1, FPT f2 )
87 // Avoid overflow.
88 if( (f2 < static_cast<FPT>(1)) && (f1 > f2*fpt_limits<FPT>::max_value()) )
89 return fpt_limits<FPT>::max_value();
91 // Avoid underflow.
92 if( (f1 == static_cast<FPT>(0)) ||
93 ((f2 > static_cast<FPT>(1)) && (f1 < f2*fpt_limits<FPT>::min_value())) )
94 return static_cast<FPT>(0);
96 return f1/f2;
99 //____________________________________________________________________________//
101 } // namespace tt_detail
103 // ************************************************************************** //
104 // ************** tolerance presentation types ************** //
105 // ************************************************************************** //
107 template<typename FPT>
108 struct percent_tolerance_t {
109 explicit percent_tolerance_t( FPT v ) : m_value( v ) {}
111 FPT m_value;
114 //____________________________________________________________________________//
116 template<typename Out,typename FPT>
117 Out& operator<<( Out& out, percent_tolerance_t<FPT> t )
119 return out << t.m_value;
122 //____________________________________________________________________________//
124 template<typename FPT>
125 inline percent_tolerance_t<FPT>
126 percent_tolerance( FPT v )
128 return percent_tolerance_t<FPT>( v );
131 //____________________________________________________________________________//
133 template<typename FPT>
134 struct fraction_tolerance_t {
135 explicit fraction_tolerance_t( FPT v ) : m_value( v ) {}
137 FPT m_value;
140 //____________________________________________________________________________//
142 template<typename Out,typename FPT>
143 Out& operator<<( Out& out, fraction_tolerance_t<FPT> t )
145 return out << t.m_value;
148 //____________________________________________________________________________//
150 template<typename FPT>
151 inline fraction_tolerance_t<FPT>
152 fraction_tolerance( FPT v )
154 return fraction_tolerance_t<FPT>( v );
157 //____________________________________________________________________________//
159 // ************************************************************************** //
160 // ************** close_at_tolerance ************** //
161 // ************************************************************************** //
163 template<typename FPT>
164 class close_at_tolerance {
165 public:
166 // Public typedefs
167 typedef bool result_type;
169 // Constructor
170 template<typename ToleranceBaseType>
171 explicit close_at_tolerance( percent_tolerance_t<ToleranceBaseType> tolerance,
172 floating_point_comparison_type fpc_type = FPC_STRONG )
173 : p_fraction_tolerance( tt_detail::fpt_abs( static_cast<FPT>(0.01)*tolerance.m_value ) )
174 , p_strong_or_weak( fpc_type == FPC_STRONG )
175 , m_report_modifier( 100. )
177 template<typename ToleranceBaseType>
178 explicit close_at_tolerance( fraction_tolerance_t<ToleranceBaseType> tolerance,
179 floating_point_comparison_type fpc_type = FPC_STRONG )
180 : p_fraction_tolerance( tt_detail::fpt_abs( tolerance.m_value ) )
181 , p_strong_or_weak( fpc_type == FPC_STRONG )
182 , m_report_modifier( 1. )
185 predicate_result operator()( FPT left, FPT right ) const
187 FPT diff = tt_detail::fpt_abs( left - right );
188 FPT d1 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( right ) );
189 FPT d2 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( left ) );
191 predicate_result res( p_strong_or_weak
192 ? (d1 <= p_fraction_tolerance.get() && d2 <= p_fraction_tolerance.get())
193 : (d1 <= p_fraction_tolerance.get() || d2 <= p_fraction_tolerance.get()) );
195 if( !res )
196 res.message() << (( d1 <= p_fraction_tolerance.get() ? d2 : d1 ) * m_report_modifier);
198 return res;
201 // Public properties
202 readonly_property<FPT> p_fraction_tolerance;
203 readonly_property<bool> p_strong_or_weak;
204 private:
205 // Data members
206 FPT m_report_modifier;
209 //____________________________________________________________________________//
211 // ************************************************************************** //
212 // ************** check_is_close ************** //
213 // ************************************************************************** //
215 struct BOOST_TEST_DECL check_is_close_t {
216 // Public typedefs
217 typedef bool result_type;
219 template<typename FPT1, typename FPT2, typename ToleranceBaseType>
220 predicate_result
221 operator()( FPT1 left, FPT2 right, percent_tolerance_t<ToleranceBaseType> tolerance,
222 floating_point_comparison_type fpc_type = FPC_STRONG ) const
224 // deduce "better" type from types of arguments being compared
225 // if one type is floating and the second integral we use floating type and
226 // value of integral type is promoted to the floating. The same for float and double
227 // But we don't want to compare two values of integral types using this tool.
228 typedef typename numeric::conversion_traits<FPT1,FPT2>::supertype FPT;
229 BOOST_STATIC_ASSERT( !is_integral<FPT>::value );
231 close_at_tolerance<FPT> pred( tolerance, fpc_type );
233 return pred( left, right );
235 template<typename FPT1, typename FPT2, typename ToleranceBaseType>
236 predicate_result
237 operator()( FPT1 left, FPT2 right, fraction_tolerance_t<ToleranceBaseType> tolerance,
238 floating_point_comparison_type fpc_type = FPC_STRONG ) const
240 // same as in a comment above
241 typedef typename numeric::conversion_traits<FPT1,FPT2>::supertype FPT;
242 BOOST_STATIC_ASSERT( !is_integral<FPT>::value );
244 close_at_tolerance<FPT> pred( tolerance, fpc_type );
246 return pred( left, right );
250 namespace {
251 check_is_close_t const& check_is_close = unit_test::ut_detail::static_constant<check_is_close_t>::value;
254 //____________________________________________________________________________//
256 // ************************************************************************** //
257 // ************** check_is_small ************** //
258 // ************************************************************************** //
260 struct BOOST_TEST_DECL check_is_small_t {
261 // Public typedefs
262 typedef bool result_type;
264 template<typename FPT>
265 bool
266 operator()( FPT fpv, FPT tolerance ) const
268 return tt_detail::fpt_abs( fpv ) < tt_detail::fpt_abs( tolerance );
272 namespace {
273 check_is_small_t const& check_is_small = unit_test::ut_detail::static_constant<check_is_small_t>::value;
276 //____________________________________________________________________________//
278 } // namespace test_tools
280 } // namespace boost
282 //____________________________________________________________________________//
284 #include <boost/test/detail/enable_warnings.hpp>
286 #endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER