Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:41

0001 //  (C) Copyright Gennadiy Rozental 2001.
0002 //  Distributed under the Boost Software License, Version 1.0.
0003 //  (See accompanying file LICENSE_1_0.txt or copy at
0004 //  http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 //  See http://www.boost.org/libs/test for the library home page.
0007 //
0008 //!@file
0009 //!@brief Floating point comparison with enhanced reporting
0010 // ***************************************************************************
0011 
0012 #ifndef BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
0013 #define BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
0014 
0015 // Boost.Test
0016 #include <boost/test/tools/assertion.hpp>
0017 
0018 #include <boost/test/tools/floating_point_comparison.hpp>
0019 #include <boost/test/tools/fpc_tolerance.hpp>
0020 
0021 // Boost
0022 #include <boost/type_traits/common_type.hpp>
0023 #include <boost/type_traits/is_arithmetic.hpp>
0024 #include <boost/utility/enable_if.hpp>
0025 
0026 #include <boost/test/detail/suppress_warnings.hpp>
0027 
0028 //____________________________________________________________________________//
0029 
0030 namespace boost {
0031 namespace test_tools {
0032 namespace assertion {
0033 namespace op {
0034 
0035 // ************************************************************************** //
0036 // **************                   fpctraits                  ************** //
0037 // ************************************************************************** //
0038 // set of floating point comparison traits per comparison OP
0039 
0040 template<typename OP>
0041 struct fpctraits {
0042     // indicate if we should perform the operation with a "logical OR"
0043     // with the "equality under tolerance".
0044     static const bool equality_logical_disjunction = true;
0045 };
0046 
0047 template <typename Lhs, typename Rhs>
0048 struct fpctraits<op::LT<Lhs,Rhs> > {
0049     static const bool equality_logical_disjunction = false;
0050 };
0051 
0052 template <typename Lhs, typename Rhs>
0053 struct fpctraits<op::GT<Lhs,Rhs> > {
0054     static const bool equality_logical_disjunction = false;
0055 };
0056 
0057 //____________________________________________________________________________//
0058 
0059 // ************************************************************************** //
0060 // ************** set of overloads to select correct fpc algo  ************** //
0061 // ************************************************************************** //
0062 // we really only care about EQ vs NE. All other comparisons use direct first
0063 // and then need EQ. For example a <= b (tolerance t) IFF a <= b OR a == b (tolerance t)
0064 
0065 template <typename FPT, typename Lhs, typename Rhs, typename OP>
0066 inline assertion_result
0067 compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* cmp_operator)
0068 {
0069     assertion_result result_direct_compare = cmp_operator->eval_direct(lhs, rhs);
0070     if(fpctraits<OP>::equality_logical_disjunction) {
0071         // this look like this can be simplified, but combining result && compare_fpv
0072         // looses the message in the return value of compare_fpv
0073         if( result_direct_compare ) {
0074             result_direct_compare.message() << "operation" << OP::forward() << "on arguments yields 'true'.";
0075             return result_direct_compare;
0076         }
0077         // result || compare_fpv(EQ)
0078         assertion_result result_eq = compare_fpv<FPT>(lhs, rhs, (op::EQ<Lhs, Rhs>*)0);
0079         result_direct_compare = result_direct_compare || result_eq;
0080         if( !result_eq ) {
0081             result_direct_compare.message() << "operation" << op::EQ<Lhs, Rhs>::forward() << "on arguments yields 'false': " << result_eq.message() << ".";
0082         }
0083         return result_direct_compare;
0084     }
0085     if( !result_direct_compare ) {
0086         result_direct_compare.message() << "operation" << OP::forward() << " on arguments yields 'false'.";
0087         return result_direct_compare;
0088     }
0089     // result && compare_fpv(NE)
0090     assertion_result result_neq = compare_fpv<FPT>(lhs, rhs, (op::NE<Lhs, Rhs>*)0);
0091     result_direct_compare = result_direct_compare && result_neq;
0092     if( !result_neq ) {
0093         result_direct_compare.message() << "operation" << op::NE<Lhs, Rhs>::forward() << "on arguments yields 'false': " << result_neq.message() << ".";
0094     }
0095     return result_direct_compare;
0096 }
0097 
0098 //____________________________________________________________________________//
0099 
0100 template <typename FPT, typename Lhs, typename Rhs>
0101 inline assertion_result
0102 compare_fpv_near_zero( FPT const& fpv, op::EQ<Lhs,Rhs>* )
0103 {
0104     fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
0105 
0106     assertion_result ar( P( fpv ) );
0107     if( !ar )
0108         ar.message() << "absolute value exceeds tolerance [|" << fpv << "| > "<< fpc_tolerance<FPT>() << ']';
0109 
0110     return ar;
0111 }
0112 
0113 //____________________________________________________________________________//
0114 
0115 template <typename FPT, typename Lhs, typename Rhs>
0116 inline assertion_result
0117 compare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* )
0118 {
0119     fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
0120 
0121     assertion_result ar( !P( fpv ) );
0122     if( !ar )
0123         ar.message() << "absolute value is within tolerance [|" << fpv << "| < "<< fpc_tolerance<FPT>() << ']';
0124     return ar;
0125 }
0126 
0127 //____________________________________________________________________________//
0128 
0129 template <typename FPT, typename Lhs, typename Rhs>
0130 inline assertion_result
0131 compare_fpv( Lhs const& lhs, Rhs const& rhs, op::EQ<Lhs,Rhs>* )
0132 {
0133     if( lhs == 0 ) {
0134         return compare_fpv_near_zero<FPT>( rhs, (op::EQ<Lhs,Rhs>*)0 );
0135     }
0136     else if( rhs == 0) {
0137         return compare_fpv_near_zero<FPT>( lhs, (op::EQ<Lhs,Rhs>*)0 );
0138     }
0139     else {
0140         fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_STRONG );
0141 
0142         assertion_result ar( P( lhs, rhs ) );
0143         if( !ar )
0144             ar.message() << "relative difference exceeds tolerance ["
0145                          << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']';
0146         return ar;
0147     }
0148 }
0149 
0150 //____________________________________________________________________________//
0151 
0152 template <typename FPT, typename Lhs, typename Rhs>
0153 inline assertion_result
0154 compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* )
0155 {
0156     if( lhs == 0 ) {
0157         return compare_fpv_near_zero<FPT>( rhs, (op::NE<Lhs,Rhs>*)0 );
0158     }
0159     else if( rhs == 0 ) {
0160         return compare_fpv_near_zero<FPT>( lhs, (op::NE<Lhs,Rhs>*)0 );
0161     }
0162     else {
0163         fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK );
0164 
0165         assertion_result ar( !P( lhs, rhs ) );
0166         if( !ar )
0167             ar.message() << "relative difference is within tolerance ["
0168                          << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']';
0169 
0170         return ar;
0171     }
0172 }
0173 
0174 //____________________________________________________________________________//
0175 
0176 #define DEFINE_FPV_COMPARISON( oper, name, rev, name_inverse )          \
0177 template<typename Lhs,typename Rhs>                                     \
0178 struct name<Lhs,Rhs,typename boost::enable_if_c<                        \
0179     (fpc::tolerance_based<Lhs>::value &&                                \
0180      fpc::tolerance_based<Rhs>::value) ||                               \
0181     (fpc::tolerance_based<Lhs>::value &&                                \
0182      boost::is_arithmetic<Rhs>::value) ||                               \
0183     (boost::is_arithmetic<Lhs>::value &&                                \
0184      fpc::tolerance_based<Rhs>::value)                                  \
0185      >::type> {                                                         \
0186 public:                                                                 \
0187     typedef typename common_type<Lhs,Rhs>::type FPT;                    \
0188     typedef name<Lhs,Rhs> OP;                                           \
0189     typedef name_inverse<Lhs, Rhs> inverse;                             \
0190                                                                         \
0191     typedef assertion_result result_type;                               \
0192                                                                         \
0193     static bool                                                         \
0194     eval_direct( Lhs const& lhs, Rhs const& rhs )                       \
0195     {                                                                   \
0196         return lhs oper rhs;                                            \
0197     }                                                                   \
0198                                                                         \
0199     static assertion_result                                             \
0200     eval( Lhs const& lhs, Rhs const& rhs )                              \
0201     {                                                                   \
0202         if( fpc_tolerance<FPT>() == FPT(0)                              \
0203             || (std::numeric_limits<Lhs>::has_infinity                  \
0204                 && (lhs == std::numeric_limits<Lhs>::infinity()))       \
0205             || (std::numeric_limits<Rhs>::has_infinity                  \
0206                 && (rhs == std::numeric_limits<Rhs>::infinity())))      \
0207         {                                                               \
0208             return eval_direct( lhs, rhs );                             \
0209         }                                                               \
0210                                                                         \
0211         return compare_fpv<FPT>( lhs, rhs, (OP*)0 );                    \
0212     }                                                                   \
0213                                                                         \
0214     template<typename PrevExprType>                                     \
0215     static void                                                         \
0216     report( std::ostream&       ostr,                                   \
0217             PrevExprType const& lhs,                                    \
0218             Rhs const&          rhs )                                   \
0219     {                                                                   \
0220         lhs.report( ostr );                                             \
0221         ostr << revert()                                                \
0222              << tt_detail::print_helper( rhs );                         \
0223     }                                                                   \
0224                                                                         \
0225     static char const* forward()                                        \
0226     { return " " #oper " "; }                                           \
0227     static char const* revert()                                         \
0228     { return " " #rev " "; }                                            \
0229 };                                                                      \
0230 /**/
0231 
0232 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_FPV_COMPARISON )
0233 #undef DEFINE_FPV_COMPARISON
0234 
0235 //____________________________________________________________________________//
0236 
0237 } // namespace op
0238 } // namespace assertion
0239 } // namespace test_tools
0240 } // namespace boost
0241 
0242 #include <boost/test/detail/enable_warnings.hpp>
0243 
0244 #endif // BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER