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 Floating point comparison with enhanced reporting
10// ***************************************************************************
11
12#ifndef BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
13#define BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
14
15// Boost.Test
16#include <boost/test/tools/assertion.hpp>
17
18#include <boost/test/tools/floating_point_comparison.hpp>
19#include <boost/test/tools/fpc_tolerance.hpp>
20
21// Boost
22#include <boost/type_traits/common_type.hpp>
23#include <boost/utility/enable_if.hpp>
24
25#include <boost/test/detail/suppress_warnings.hpp>
26
27//____________________________________________________________________________//
28
29namespace boost {
30namespace test_tools {
31namespace assertion {
32namespace op {
33
34// ************************************************************************** //
35// ************** fpctraits ************** //
36// ************************************************************************** //
37// set of floating point comparison traits per comparison OP
38
39template<typename OP>
40struct fpctraits {
41 static const bool cmp_direct = true;
42};
43
44template <typename Lhs, typename Rhs>
45struct fpctraits<op::NE<Lhs,Rhs> > {
46 static const bool cmp_direct = false;
47};
48
49template <typename Lhs, typename Rhs>
50struct fpctraits<op::LT<Lhs,Rhs> > {
51 static const bool cmp_direct = false;
52};
53
54template <typename Lhs, typename Rhs>
55struct fpctraits<op::GT<Lhs,Rhs> > {
56 static const bool cmp_direct = false;
57};
58
59//____________________________________________________________________________//
60
61// ************************************************************************** //
62// ************** set of overloads to select correct fpc algo ************** //
63// ************************************************************************** //
64// we really only care about EQ vs NE. All other comparisons use direct first
65// and then need EQ. For example a < b (tolerance t) IFF a < b OR a == b (tolerance t)
66
67template <typename FPT, typename Lhs, typename Rhs, typename OP>
68inline assertion_result
69compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* )
70{
71 fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_STRONG );
72
73 assertion_result ar( P( lhs, rhs ) );
74 if( !ar )
75 ar.message() << "Relative difference exceeds tolerance ["
76 << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']';
77 return ar;
78}
79
80//____________________________________________________________________________//
81
82template <typename FPT, typename OP>
83inline assertion_result
84compare_fpv_near_zero( FPT const& fpv, OP* )
85{
86 fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
87
88 assertion_result ar( P( fpv ) );
89 if( !ar )
90 ar.message() << "Absolute value exceeds tolerance [|" << fpv << "| > "<< fpc_tolerance<FPT>() << ']';
91
92 return ar;
93}
94
95//____________________________________________________________________________//
96
97template <typename FPT, typename Lhs, typename Rhs>
98inline assertion_result
99compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* )
100{
101 fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK );
102
103 assertion_result ar( !P( lhs, rhs ) );
104 if( !ar )
105 ar.message() << "Relative difference is within tolerance ["
106 << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']';
107
108 return ar;
109}
110
111//____________________________________________________________________________//
112
113template <typename FPT, typename Lhs, typename Rhs>
114inline assertion_result
115compare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* )
116{
117 fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
118
119 assertion_result ar( !P( fpv ) );
120 if( !ar )
121 ar.message() << "Absolute value is within tolerance [|" << fpv << "| < "<< fpc_tolerance<FPT>() << ']';
122 return ar;
123}
124
125//____________________________________________________________________________//
126
127template <typename FPT, typename Lhs, typename Rhs>
128inline assertion_result
129compare_fpv( Lhs const& lhs, Rhs const& rhs, op::LT<Lhs,Rhs>* )
130{
131 return lhs >= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
132}
133
134template <typename FPT, typename Lhs, typename Rhs>
135inline assertion_result
136compare_fpv_near_zero( FPT const& fpv, op::LT<Lhs,Rhs>* )
137{
138 return fpv >= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
139}
140
141//____________________________________________________________________________//
142
143template <typename FPT, typename Lhs, typename Rhs>
144inline assertion_result
145compare_fpv( Lhs const& lhs, Rhs const& rhs, op::GT<Lhs,Rhs>* )
146{
147 return lhs <= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
148}
149
150template <typename FPT, typename Lhs, typename Rhs>
151inline assertion_result
152compare_fpv_near_zero( FPT const& fpv, op::GT<Lhs,Rhs>* )
153{
154 return fpv <= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
155}
156
157
158//____________________________________________________________________________//
159
160#define DEFINE_FPV_COMPARISON( oper, name, rev ) \
161template<typename Lhs,typename Rhs> \
162struct name<Lhs,Rhs,typename boost::enable_if_c< \
163 (fpc::tolerance_based<Lhs>::value && \
164 fpc::tolerance_based<Rhs>::value)>::type> { \
165public: \
166 typedef typename common_type<Lhs,Rhs>::type FPT; \
167 typedef name<Lhs,Rhs> OP; \
168 \
169 typedef assertion_result result_type; \
170 \
171 static bool \
172 eval_direct( Lhs const& lhs, Rhs const& rhs ) \
173 { \
174 return lhs oper rhs; \
175 } \
176 \
177 static assertion_result \
178 eval( Lhs const& lhs, Rhs const& rhs ) \
179 { \
180 if( lhs == 0 ) \
181 return compare_fpv_near_zero( rhs, (OP*)0 ); \
182 \
183 if( rhs == 0 ) \
184 return compare_fpv_near_zero( lhs, (OP*)0 ); \
185 \
186 bool direct_res = eval_direct( lhs, rhs ); \
187 \
188 if( (direct_res && fpctraits<OP>::cmp_direct) || \
189 fpc_tolerance<FPT>() == FPT(0) ) \
190 return direct_res; \
191 \
192 return compare_fpv<FPT>( lhs, rhs, (OP*)0 ); \
193 } \
194 \
195 template<typename PrevExprType> \
196 static void \
197 report( std::ostream& ostr, \
198 PrevExprType const& lhs, \
199 Rhs const& rhs ) \
200 { \
201 lhs.report( ostr ); \
202 ostr << revert() \
203 << tt_detail::print_helper( rhs ); \
204 } \
205 \
206 static char const* revert() \
207 { return " " #rev " "; } \
208}; \
209/**/
210
211BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_FPV_COMPARISON )
212#undef DEFINE_FPV_COMPARISON
213
214//____________________________________________________________________________//
215
216} // namespace op
217} // namespace assertion
218} // namespace test_tools
219} // namespace boost
220
221#include <boost/test/detail/enable_warnings.hpp>
222
223#endif // BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
224
225