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.
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
19 #include <boost/test/detail/global_typedef.hpp>
20 #include <boost/test/utils/class_properties.hpp>
21 #include <boost/test/predicate_result.hpp>
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 //____________________________________________________________________________//
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 // ************************************************************************** //
54 // FPT is Floating-Point Type: float, double, long double or User-Defined.
55 template<typename FPT
>
59 return arg
< static_cast<FPT
>(0) ? -arg
: arg
;
62 //____________________________________________________________________________//
64 template<typename FPT
>
66 static FPT
min_value()
68 return std::numeric_limits
<FPT
>::is_specialized
69 ? (std::numeric_limits
<FPT
>::min
)()
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
>
85 safe_fpt_division( FPT f1
, FPT f2
)
88 if( (f2
< static_cast<FPT
>(1)) && (f1
> f2
*fpt_limits
<FPT
>::max_value()) )
89 return fpt_limits
<FPT
>::max_value();
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);
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
) {}
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
) {}
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
{
167 typedef bool result_type
;
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()) );
196 res
.message() << (( d1
<= p_fraction_tolerance
.get() ? d2
: d1
) * m_report_modifier
);
202 readonly_property
<FPT
> p_fraction_tolerance
;
203 readonly_property
<bool> p_strong_or_weak
;
206 FPT m_report_modifier
;
209 //____________________________________________________________________________//
211 // ************************************************************************** //
212 // ************** check_is_close ************** //
213 // ************************************************************************** //
215 struct BOOST_TEST_DECL check_is_close_t
{
217 typedef bool result_type
;
219 template<typename FPT1
, typename FPT2
, typename ToleranceBaseType
>
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
>
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
);
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
{
262 typedef bool result_type
;
264 template<typename FPT
>
266 operator()( FPT fpv
, FPT tolerance
) const
268 return tt_detail::fpt_abs( fpv
) < tt_detail::fpt_abs( tolerance
);
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
282 //____________________________________________________________________________//
284 #include <boost/test/detail/enable_warnings.hpp>
286 #endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER