fpc_op.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // (C) Copyright Gennadiy Rozental 2001.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. //!@file
  8. //!@brief Floating point comparison with enhanced reporting
  9. // ***************************************************************************
  10. #ifndef BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
  11. #define BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER
  12. // Boost.Test
  13. #include <boost/test/tools/assertion.hpp>
  14. #include <boost/test/tools/floating_point_comparison.hpp>
  15. #include <boost/test/tools/fpc_tolerance.hpp>
  16. // Boost
  17. #include <boost/type_traits/common_type.hpp>
  18. #include <boost/utility/enable_if.hpp>
  19. #include <boost/test/detail/suppress_warnings.hpp>
  20. //____________________________________________________________________________//
  21. namespace boost {
  22. namespace test_tools {
  23. namespace assertion {
  24. namespace op {
  25. // ************************************************************************** //
  26. // ************** fpctraits ************** //
  27. // ************************************************************************** //
  28. // set of floating point comparison traits per comparison OP
  29. template<typename OP>
  30. struct fpctraits {
  31. static const bool cmp_direct = true;
  32. };
  33. template <typename Lhs, typename Rhs>
  34. struct fpctraits<op::NE<Lhs,Rhs> > {
  35. static const bool cmp_direct = false;
  36. };
  37. template <typename Lhs, typename Rhs>
  38. struct fpctraits<op::LT<Lhs,Rhs> > {
  39. static const bool cmp_direct = false;
  40. };
  41. template <typename Lhs, typename Rhs>
  42. struct fpctraits<op::GT<Lhs,Rhs> > {
  43. static const bool cmp_direct = false;
  44. };
  45. //____________________________________________________________________________//
  46. // ************************************************************************** //
  47. // ************** set of overloads to select correct fpc algo ************** //
  48. // ************************************************************************** //
  49. // we really only care about EQ vs NE. All other comparisons use direct first
  50. // and then need EQ. For example a < b (tolerance t) IFF a < b OR a == b (tolerance t)
  51. template <typename FPT, typename Lhs, typename Rhs, typename OP>
  52. inline assertion_result
  53. compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* )
  54. {
  55. fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_STRONG );
  56. assertion_result ar( P( lhs, rhs ) );
  57. if( !ar )
  58. ar.message() << "Relative difference exceeds tolerance ["
  59. << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']';
  60. return ar;
  61. }
  62. //____________________________________________________________________________//
  63. template <typename FPT, typename OP>
  64. inline assertion_result
  65. compare_fpv_near_zero( FPT const& fpv, OP* )
  66. {
  67. fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
  68. assertion_result ar( P( fpv ) );
  69. if( !ar )
  70. ar.message() << "Absolute value exceeds tolerance [|" << fpv << "| > "<< fpc_tolerance<FPT>() << ']';
  71. return ar;
  72. }
  73. //____________________________________________________________________________//
  74. template <typename FPT, typename Lhs, typename Rhs>
  75. inline assertion_result
  76. compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* )
  77. {
  78. fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK );
  79. assertion_result ar( !P( lhs, rhs ) );
  80. if( !ar )
  81. ar.message() << "Relative difference is within tolerance ["
  82. << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']';
  83. return ar;
  84. }
  85. //____________________________________________________________________________//
  86. template <typename FPT, typename Lhs, typename Rhs>
  87. inline assertion_result
  88. compare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* )
  89. {
  90. fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() );
  91. assertion_result ar( !P( fpv ) );
  92. if( !ar )
  93. ar.message() << "Absolute value is within tolerance [|" << fpv << "| < "<< fpc_tolerance<FPT>() << ']';
  94. return ar;
  95. }
  96. //____________________________________________________________________________//
  97. template <typename FPT, typename Lhs, typename Rhs>
  98. inline assertion_result
  99. compare_fpv( Lhs const& lhs, Rhs const& rhs, op::LT<Lhs,Rhs>* )
  100. {
  101. return lhs >= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
  102. }
  103. template <typename FPT, typename Lhs, typename Rhs>
  104. inline assertion_result
  105. compare_fpv_near_zero( FPT const& fpv, op::LT<Lhs,Rhs>* )
  106. {
  107. return fpv >= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
  108. }
  109. //____________________________________________________________________________//
  110. template <typename FPT, typename Lhs, typename Rhs>
  111. inline assertion_result
  112. compare_fpv( Lhs const& lhs, Rhs const& rhs, op::GT<Lhs,Rhs>* )
  113. {
  114. return lhs <= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 );
  115. }
  116. template <typename FPT, typename Lhs, typename Rhs>
  117. inline assertion_result
  118. compare_fpv_near_zero( FPT const& fpv, op::GT<Lhs,Rhs>* )
  119. {
  120. return fpv <= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 );
  121. }
  122. //____________________________________________________________________________//
  123. #define DEFINE_FPV_COMPARISON( oper, name, rev ) \
  124. template<typename Lhs,typename Rhs> \
  125. struct name<Lhs,Rhs,typename boost::enable_if_c< \
  126. (fpc::tolerance_based<Lhs>::value && \
  127. fpc::tolerance_based<Rhs>::value)>::type> { \
  128. public: \
  129. typedef typename common_type<Lhs,Rhs>::type FPT; \
  130. typedef name<Lhs,Rhs> OP; \
  131. \
  132. typedef assertion_result result_type; \
  133. \
  134. static bool \
  135. eval_direct( Lhs const& lhs, Rhs const& rhs ) \
  136. { \
  137. return lhs oper rhs; \
  138. } \
  139. \
  140. static assertion_result \
  141. eval( Lhs const& lhs, Rhs const& rhs ) \
  142. { \
  143. if( lhs == 0 ) \
  144. return compare_fpv_near_zero( rhs, (OP*)0 ); \
  145. \
  146. if( rhs == 0 ) \
  147. return compare_fpv_near_zero( lhs, (OP*)0 ); \
  148. \
  149. bool direct_res = eval_direct( lhs, rhs ); \
  150. \
  151. if( (direct_res && fpctraits<OP>::cmp_direct) || \
  152. fpc_tolerance<FPT>() == FPT(0) ) \
  153. return direct_res; \
  154. \
  155. return compare_fpv<FPT>( lhs, rhs, (OP*)0 ); \
  156. } \
  157. \
  158. template<typename PrevExprType> \
  159. static void \
  160. report( std::ostream& ostr, \
  161. PrevExprType const& lhs, \
  162. Rhs const& rhs ) \
  163. { \
  164. lhs.report( ostr ); \
  165. ostr << revert() \
  166. << tt_detail::print_helper( rhs ); \
  167. } \
  168. \
  169. static char const* revert() \
  170. { return " " #rev " "; } \
  171. }; \
  172. /**/
  173. BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_FPV_COMPARISON )
  174. #undef DEFINE_FPV_COMPARISON
  175. //____________________________________________________________________________//
  176. } // namespace op
  177. } // namespace assertion
  178. } // namespace test_tools
  179. } // namespace boost
  180. #include <boost/test/detail/enable_warnings.hpp>
  181. #endif // BOOST_TEST_TOOLS_FPC_OP_HPP_050915GER