summaryrefslogtreecommitdiff
path: root/boost/test/tools/fpc_op.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/test/tools/fpc_op.hpp')
-rw-r--r--boost/test/tools/fpc_op.hpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/boost/test/tools/fpc_op.hpp b/boost/test/tools/fpc_op.hpp
new file mode 100644
index 0000000000..a2513ccfa3
--- /dev/null
+++ b/boost/test/tools/fpc_op.hpp
@@ -0,0 +1,224 @@
+// (C) Copyright Gennadiy Rozental 2014-2015.
+// 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
+