// (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 { // indicate if we should perform the operation with a "logical OR" // with the "equality under tolerance". static const bool equality_logical_disjunction = true; }; template struct fpctraits > { static const bool equality_logical_disjunction = false; }; template struct fpctraits > { static const bool equality_logical_disjunction = 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* cmp_operator) { bool result = cmp_operator->eval_direct(lhs, rhs); if(fpctraits::equality_logical_disjunction) { return result || compare_fpv(lhs, rhs, (op::EQ*)0); } return result && compare_fpv(lhs, rhs, (op::NE*)0); } //____________________________________________________________________________// template inline assertion_result compare_fpv_near_zero( FPT const& fpv, op::EQ* ) { 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_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::EQ* ) { if( lhs == 0 ) { return compare_fpv_near_zero( rhs, (op::EQ*)0 ); } else if( rhs == 0) { return compare_fpv_near_zero( lhs, (op::EQ*)0 ); } else { 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( Lhs const& lhs, Rhs const& rhs, op::NE* ) { if( lhs == 0 ) { return compare_fpv_near_zero( rhs, (op::NE*)0 ); } else if( rhs == 0 ) { return compare_fpv_near_zero( lhs, (op::NE*)0 ); } else { 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; } } //____________________________________________________________________________// #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( fpc_tolerance() == FPT(0) ) \ { \ return eval_direct( lhs, rhs ); \ } \ \ 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