// (C) Copyright Gennadiy Rozental 2001. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/test for the library home page. // //!@file //!@brief Floating point comparison with enhanced reporting // *************************************************************************** #ifndef BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER #define BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER // Boost.Test #include #include #include // Boost #include #include #include //____________________________________________________________________________// namespace boost { namespace test_tools { namespace assertion { namespace op { // ************************************************************************** // // ************** fpctraits ************** // // ************************************************************************** // // set of floating point comparison traits per comparison OP template struct fpctraits { static const bool cmp_direct = true; }; template struct fpctraits > { static const bool cmp_direct = false; }; template struct fpctraits > { static const bool cmp_direct = false; }; template struct fpctraits > { static const bool cmp_direct = false; }; //____________________________________________________________________________// // ************************************************************************** // // ************** set of overloads to select correct fpc algo ************** // // ************************************************************************** // // we really only care about EQ vs NE. All other comparisons use direct first // and then need EQ. For example a < b (tolerance t) IFF a < b OR a == b (tolerance t) template inline assertion_result compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* ) { fpc::close_at_tolerance P( fpc_tolerance(), fpc::FPC_STRONG ); assertion_result ar( P( lhs, rhs ) ); if( !ar ) ar.message() << "Relative difference exceeds tolerance [" << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']'; return ar; } //____________________________________________________________________________// template inline assertion_result compare_fpv_near_zero( FPT const& fpv, OP* ) { fpc::small_with_tolerance P( fpc_tolerance() ); assertion_result ar( P( fpv ) ); if( !ar ) ar.message() << "Absolute value exceeds tolerance [|" << fpv << "| > "<< fpc_tolerance() << ']'; return ar; } //____________________________________________________________________________// template inline assertion_result compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE* ) { fpc::close_at_tolerance P( fpc_tolerance(), fpc::FPC_WEAK ); assertion_result ar( !P( lhs, rhs ) ); if( !ar ) ar.message() << "Relative difference is within tolerance [" << P.tested_rel_diff() << " < " << fpc_tolerance() << ']'; return ar; } //____________________________________________________________________________// template inline assertion_result compare_fpv_near_zero( FPT const& fpv, op::NE* ) { fpc::small_with_tolerance P( fpc_tolerance() ); assertion_result ar( !P( fpv ) ); if( !ar ) ar.message() << "Absolute value is within tolerance [|" << fpv << "| < "<< fpc_tolerance() << ']'; return ar; } //____________________________________________________________________________// template inline assertion_result compare_fpv( Lhs const& lhs, Rhs const& rhs, op::LT* ) { return lhs >= rhs ? assertion_result( false ) : compare_fpv( lhs, rhs, (op::NE*)0 ); } template inline assertion_result compare_fpv_near_zero( FPT const& fpv, op::LT* ) { return fpv >= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE*)0 ); } //____________________________________________________________________________// template inline assertion_result compare_fpv( Lhs const& lhs, Rhs const& rhs, op::GT* ) { return lhs <= rhs ? assertion_result( false ) : compare_fpv( lhs, rhs, (op::NE*)0 ); } template inline assertion_result compare_fpv_near_zero( FPT const& fpv, op::GT* ) { return fpv <= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE*)0 ); } //____________________________________________________________________________// #define DEFINE_FPV_COMPARISON( oper, name, rev ) \ template \ struct name::value && \ fpc::tolerance_based::value)>::type> { \ public: \ typedef typename common_type::type FPT; \ typedef name OP; \ \ typedef assertion_result result_type; \ \ static bool \ eval_direct( Lhs const& lhs, Rhs const& rhs ) \ { \ return lhs oper rhs; \ } \ \ static assertion_result \ eval( Lhs const& lhs, Rhs const& rhs ) \ { \ if( lhs == 0 ) \ { \ return compare_fpv_near_zero( rhs, (OP*)0 ); \ } \ \ if( rhs == 0 ) \ { \ return compare_fpv_near_zero( lhs, (OP*)0 ); \ } \ \ bool direct_res = eval_direct( lhs, rhs ); \ \ if( (direct_res && fpctraits::cmp_direct) || \ fpc_tolerance() == FPT(0) ) \ { \ return direct_res; \ } \ \ return compare_fpv( lhs, rhs, (OP*)0 ); \ } \ \ template \ static void \ report( std::ostream& ostr, \ PrevExprType const& lhs, \ Rhs const& rhs ) \ { \ lhs.report( ostr ); \ ostr << revert() \ << tt_detail::print_helper( rhs ); \ } \ \ static char const* revert() \ { return " " #rev " "; } \ }; \ /**/ BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_FPV_COMPARISON ) #undef DEFINE_FPV_COMPARISON //____________________________________________________________________________// } // namespace op } // namespace assertion } // namespace test_tools } // namespace boost #include #endif // BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER