231 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
//  (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/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 OP
 | 
						|
 | 
						|
template<typename OP>
 | 
						|
struct fpctraits {
 | 
						|
    static const bool cmp_direct = true;
 | 
						|
};
 | 
						|
 | 
						|
template <typename Lhs, typename Rhs>
 | 
						|
struct fpctraits<op::NE<Lhs,Rhs> > {
 | 
						|
    static const bool cmp_direct = false;
 | 
						|
};
 | 
						|
 | 
						|
template <typename Lhs, typename Rhs>
 | 
						|
struct fpctraits<op::LT<Lhs,Rhs> > {
 | 
						|
    static const bool cmp_direct = false;
 | 
						|
};
 | 
						|
 | 
						|
template <typename Lhs, typename Rhs>
 | 
						|
struct fpctraits<op::GT<Lhs,Rhs> > {
 | 
						|
    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 <typename FPT, typename Lhs, typename Rhs, typename OP>
 | 
						|
inline assertion_result
 | 
						|
compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* )
 | 
						|
{
 | 
						|
    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 OP>
 | 
						|
inline assertion_result
 | 
						|
compare_fpv_near_zero( FPT const& fpv, OP* )
 | 
						|
{
 | 
						|
    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_result
 | 
						|
compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* )
 | 
						|
{
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
//____________________________________________________________________________//
 | 
						|
 | 
						|
template <typename FPT, typename Lhs, typename Rhs>
 | 
						|
inline assertion_result
 | 
						|
compare_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_result
 | 
						|
compare_fpv( Lhs const& lhs, Rhs const& rhs, op::LT<Lhs,Rhs>* )
 | 
						|
{
 | 
						|
    return lhs >= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
 | 
						|
}
 | 
						|
 | 
						|
template <typename FPT, typename Lhs, typename Rhs>
 | 
						|
inline assertion_result
 | 
						|
compare_fpv_near_zero( FPT const& fpv, op::LT<Lhs,Rhs>* )
 | 
						|
{
 | 
						|
    return fpv >= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
 | 
						|
}
 | 
						|
 | 
						|
//____________________________________________________________________________//
 | 
						|
 | 
						|
template <typename FPT, typename Lhs, typename Rhs>
 | 
						|
inline assertion_result
 | 
						|
compare_fpv( Lhs const& lhs, Rhs const& rhs, op::GT<Lhs,Rhs>* )
 | 
						|
{
 | 
						|
    return lhs <= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
 | 
						|
}
 | 
						|
 | 
						|
template <typename FPT, typename Lhs, typename Rhs>
 | 
						|
inline assertion_result
 | 
						|
compare_fpv_near_zero( FPT const& fpv, op::GT<Lhs,Rhs>* )
 | 
						|
{
 | 
						|
    return fpv <= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//____________________________________________________________________________//
 | 
						|
 | 
						|
#define DEFINE_FPV_COMPARISON( oper, name, rev )                        \
 | 
						|
template<typename Lhs,typename Rhs>                                     \
 | 
						|
struct name<Lhs,Rhs,typename boost::enable_if_c<                        \
 | 
						|
    (fpc::tolerance_based<Lhs>::value &&                                \
 | 
						|
     fpc::tolerance_based<Rhs>::value)>::type> {                        \
 | 
						|
public:                                                                 \
 | 
						|
    typedef typename common_type<Lhs,Rhs>::type FPT;                    \
 | 
						|
    typedef name<Lhs,Rhs> 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<OP>::cmp_direct) ||                \
 | 
						|
            fpc_tolerance<FPT>() == FPT(0) )                            \
 | 
						|
        {                                                               \
 | 
						|
            return direct_res;                                          \
 | 
						|
        }                                                               \
 | 
						|
                                                                        \
 | 
						|
        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* 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
 | 
						|
 |