| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 | //  (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 <boost/test/tools/assertion.hpp>#include <boost/test/tools/floating_point_comparison.hpp>#include <boost/test/tools/fpc_tolerance.hpp>// Boost#include <boost/type_traits/common_type.hpp>#include <boost/type_traits/is_arithmetic.hpp>#include <boost/utility/enable_if.hpp>#include <boost/test/detail/suppress_warnings.hpp>//____________________________________________________________________________//namespace boost {namespace test_tools {namespace assertion {namespace op {// ************************************************************************** //// **************                   fpctraits                  ************** //// ************************************************************************** //// set of floating point comparison traits per comparison OPtemplate<typename OP>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 <typename Lhs, typename Rhs>struct fpctraits<op::LT<Lhs,Rhs> > {    static const bool equality_logical_disjunction = false;};template <typename Lhs, typename Rhs>struct fpctraits<op::GT<Lhs,Rhs> > {    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 <typename FPT, typename Lhs, typename Rhs, typename OP>inline assertion_resultcompare_fpv( Lhs const& lhs, Rhs const& rhs, OP* cmp_operator){    assertion_result result_direct_compare = cmp_operator->eval_direct(lhs, rhs);    if(fpctraits<OP>::equality_logical_disjunction) {        // this look like this can be simplified, but combining result && compare_fpv        // looses the message in the return value of compare_fpv        if( result_direct_compare ) {            result_direct_compare.message() << "operation" << OP::forward() << "on arguments yields 'true'.";            return result_direct_compare;        }        // result || compare_fpv(EQ)        assertion_result result_eq = compare_fpv<FPT>(lhs, rhs, (op::EQ<Lhs, Rhs>*)0);        result_direct_compare = result_direct_compare || result_eq;        if( !result_eq ) {            result_direct_compare.message() << "operation" << op::EQ<Lhs, Rhs>::forward() << "on arguments yields 'false': " << result_eq.message() << ".";        }        return result_direct_compare;    }    if( !result_direct_compare ) {        result_direct_compare.message() << "operation" << OP::forward() << " on arguments yields 'false'.";        return result_direct_compare;    }    // result && compare_fpv(NE)    assertion_result result_neq = compare_fpv<FPT>(lhs, rhs, (op::NE<Lhs, Rhs>*)0);    result_direct_compare = result_direct_compare && result_neq;    if( !result_neq ) {        result_direct_compare.message() << "operation" << op::NE<Lhs, Rhs>::forward() << "on arguments yields 'false': " << result_neq.message() << ".";    }    return result_direct_compare;}//____________________________________________________________________________//template <typename FPT, typename Lhs, typename Rhs>inline assertion_resultcompare_fpv_near_zero( FPT const& fpv, op::EQ<Lhs,Rhs>* ){    fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );    assertion_result ar( P( fpv ) );    if( !ar )        ar.message() << "absolute value exceeds tolerance [|" << fpv << "| > "<< fpc_tolerance<FPT>() << ']';    return ar;}//____________________________________________________________________________//template <typename FPT, typename Lhs, typename Rhs>inline assertion_resultcompare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* ){    fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );    assertion_result ar( !P( fpv ) );    if( !ar )        ar.message() << "absolute value is within tolerance [|" << fpv << "| < "<< fpc_tolerance<FPT>() << ']';    return ar;}//____________________________________________________________________________//template <typename FPT, typename Lhs, typename Rhs>inline assertion_resultcompare_fpv( Lhs const& lhs, Rhs const& rhs, op::EQ<Lhs,Rhs>* ){    if( lhs == 0 ) {        return compare_fpv_near_zero<FPT>( rhs, (op::EQ<Lhs,Rhs>*)0 );    }    else if( rhs == 0) {        return compare_fpv_near_zero<FPT>( lhs, (op::EQ<Lhs,Rhs>*)0 );    }    else {        fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), 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 <typename FPT, typename Lhs, typename Rhs>inline assertion_resultcompare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* ){    if( lhs == 0 ) {        return compare_fpv_near_zero<FPT>( rhs, (op::NE<Lhs,Rhs>*)0 );    }    else if( rhs == 0 ) {        return compare_fpv_near_zero<FPT>( lhs, (op::NE<Lhs,Rhs>*)0 );    }    else {        fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK );        assertion_result ar( !P( lhs, rhs ) );        if( !ar )            ar.message() << "relative difference is within tolerance ["                         << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']';        return ar;    }}//____________________________________________________________________________//#define DEFINE_FPV_COMPARISON( oper, name, rev, name_inverse )          \template<typename Lhs,typename Rhs>                                     \struct name<Lhs,Rhs,typename boost::enable_if_c<                        \    (fpc::tolerance_based<Lhs>::value &&                                \     fpc::tolerance_based<Rhs>::value) ||                               \    (fpc::tolerance_based<Lhs>::value &&                                \     boost::is_arithmetic<Rhs>::value) ||                               \    (boost::is_arithmetic<Lhs>::value &&                                \     fpc::tolerance_based<Rhs>::value)                                  \     >::type> {                                                         \public:                                                                 \    typedef typename common_type<Lhs,Rhs>::type FPT;                    \    typedef name<Lhs,Rhs> OP;                                           \    typedef name_inverse<Lhs, Rhs> inverse;                             \                                                                        \    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>() == FPT(0)                              \            || (std::numeric_limits<Lhs>::has_infinity                  \                && (lhs == std::numeric_limits<Lhs>::infinity()))       \            || (std::numeric_limits<Rhs>::has_infinity                  \                && (rhs == std::numeric_limits<Rhs>::infinity())))      \        {                                                               \            return eval_direct( lhs, rhs );                             \        }                                                               \                                                                        \        return compare_fpv<FPT>( lhs, rhs, (OP*)0 );                    \    }                                                                   \                                                                        \    template<typename PrevExprType>                                     \    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* forward()                                        \    { return " " #oper " "; }                                           \    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 <boost/test/detail/enable_warnings.hpp>#endif // BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
 |