| 1 | // (C) Copyright Gennadiy Rozental 2001-2005. |
|---|
| 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 | |
|---|
| 6 | // See http://www.boost.org/libs/test for the library home page. |
|---|
| 7 | // |
|---|
| 8 | // File : $RCSfile: floating_point_comparison.hpp,v $ |
|---|
| 9 | // |
|---|
| 10 | // Version : $Revision: 1.26.2.2 $ |
|---|
| 11 | // |
|---|
| 12 | // Description : defines algoirthms for comparing 2 floating point values |
|---|
| 13 | // *************************************************************************** |
|---|
| 14 | |
|---|
| 15 | #ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER |
|---|
| 16 | #define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER |
|---|
| 17 | |
|---|
| 18 | #include <boost/limits.hpp> // for std::numeric_limits |
|---|
| 19 | |
|---|
| 20 | #include <boost/test/utils/class_properties.hpp> |
|---|
| 21 | |
|---|
| 22 | #include <boost/test/detail/suppress_warnings.hpp> |
|---|
| 23 | |
|---|
| 24 | //____________________________________________________________________________// |
|---|
| 25 | |
|---|
| 26 | namespace boost { |
|---|
| 27 | |
|---|
| 28 | namespace test_tools { |
|---|
| 29 | |
|---|
| 30 | using unit_test::readonly_property; |
|---|
| 31 | |
|---|
| 32 | // ************************************************************************** // |
|---|
| 33 | // ************** floating_point_comparison_type ************** // |
|---|
| 34 | // ************************************************************************** // |
|---|
| 35 | |
|---|
| 36 | enum floating_point_comparison_type { |
|---|
| 37 | FPC_STRONG, // "Very close" - equation 1' in docs, the default |
|---|
| 38 | FPC_WEAK // "Close enough" - equation 2' in docs. |
|---|
| 39 | |
|---|
| 40 | }; |
|---|
| 41 | |
|---|
| 42 | // ************************************************************************** // |
|---|
| 43 | // ************** details ************** // |
|---|
| 44 | // ************************************************************************** // |
|---|
| 45 | |
|---|
| 46 | namespace tt_detail { |
|---|
| 47 | |
|---|
| 48 | // FPT is Floating-Point type, float, double, long double or User-Defined. |
|---|
| 49 | |
|---|
| 50 | template<typename FPT> |
|---|
| 51 | inline FPT |
|---|
| 52 | fpt_abs( FPT arg ) |
|---|
| 53 | { |
|---|
| 54 | return arg < static_cast<FPT>(0) ? -arg : arg; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | //____________________________________________________________________________// |
|---|
| 58 | |
|---|
| 59 | // both f1 and f2 are unsigned here |
|---|
| 60 | template<typename FPT> |
|---|
| 61 | inline FPT |
|---|
| 62 | safe_fpt_division( FPT f1, FPT f2 ) |
|---|
| 63 | { |
|---|
| 64 | // Avoid overflow. |
|---|
| 65 | if( f2 < static_cast<FPT>(1) && f1 > f2 * (std::numeric_limits<FPT>::max)() ) |
|---|
| 66 | return (std::numeric_limits<FPT>::max)(); |
|---|
| 67 | |
|---|
| 68 | // Avoid underflow. |
|---|
| 69 | if( f1 == static_cast<FPT>(0) || |
|---|
| 70 | f2 > static_cast<FPT>(1) && f1 < f2 * (std::numeric_limits<FPT>::min)() ) |
|---|
| 71 | return static_cast<FPT>(0); |
|---|
| 72 | |
|---|
| 73 | return f1/f2; |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | //____________________________________________________________________________// |
|---|
| 77 | |
|---|
| 78 | } // namespace tt_detail |
|---|
| 79 | |
|---|
| 80 | // ************************************************************************** // |
|---|
| 81 | // ************** tolerance presentation types ************** // |
|---|
| 82 | // ************************************************************************** // |
|---|
| 83 | |
|---|
| 84 | template<typename FPT> |
|---|
| 85 | struct percent_tolerance_t { |
|---|
| 86 | explicit percent_tolerance_t( FPT v ) : m_value( v ) {} |
|---|
| 87 | |
|---|
| 88 | FPT m_value; |
|---|
| 89 | }; |
|---|
| 90 | |
|---|
| 91 | //____________________________________________________________________________// |
|---|
| 92 | |
|---|
| 93 | template<typename Out,typename FPT> |
|---|
| 94 | Out& operator<<( Out& out, percent_tolerance_t<FPT> t ) |
|---|
| 95 | { |
|---|
| 96 | return out << t.m_value; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | //____________________________________________________________________________// |
|---|
| 100 | |
|---|
| 101 | template<typename FPT> |
|---|
| 102 | inline percent_tolerance_t<FPT> |
|---|
| 103 | percent_tolerance( FPT v ) |
|---|
| 104 | { |
|---|
| 105 | return percent_tolerance_t<FPT>( v ); |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | //____________________________________________________________________________// |
|---|
| 109 | |
|---|
| 110 | template<typename FPT> |
|---|
| 111 | struct fraction_tolerance_t { |
|---|
| 112 | explicit fraction_tolerance_t( FPT v ) : m_value( v ) {} |
|---|
| 113 | |
|---|
| 114 | FPT m_value; |
|---|
| 115 | }; |
|---|
| 116 | |
|---|
| 117 | //____________________________________________________________________________// |
|---|
| 118 | |
|---|
| 119 | template<typename Out,typename FPT> |
|---|
| 120 | Out& operator<<( Out& out, fraction_tolerance_t<FPT> t ) |
|---|
| 121 | { |
|---|
| 122 | return out << t.m_value; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | //____________________________________________________________________________// |
|---|
| 126 | |
|---|
| 127 | template<typename FPT> |
|---|
| 128 | inline fraction_tolerance_t<FPT> |
|---|
| 129 | fraction_tolerance( FPT v ) |
|---|
| 130 | { |
|---|
| 131 | return fraction_tolerance_t<FPT>( v ); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | //____________________________________________________________________________// |
|---|
| 135 | |
|---|
| 136 | // ************************************************************************** // |
|---|
| 137 | // ************** close_at_tolerance ************** // |
|---|
| 138 | // ************************************************************************** // |
|---|
| 139 | |
|---|
| 140 | template<typename FPT> |
|---|
| 141 | class close_at_tolerance { |
|---|
| 142 | public: |
|---|
| 143 | // Public typedefs |
|---|
| 144 | typedef bool result_type; |
|---|
| 145 | |
|---|
| 146 | // Constructor |
|---|
| 147 | template<typename ToleranceBaseType> |
|---|
| 148 | explicit close_at_tolerance( percent_tolerance_t<ToleranceBaseType> tolerance, |
|---|
| 149 | floating_point_comparison_type fpc_type = FPC_STRONG ) |
|---|
| 150 | : p_fraction_tolerance( tt_detail::fpt_abs( static_cast<FPT>(0.01)*tolerance.m_value ) ) |
|---|
| 151 | , p_strong_or_weak( fpc_type == FPC_STRONG ) |
|---|
| 152 | {} |
|---|
| 153 | template<typename ToleranceBaseType> |
|---|
| 154 | explicit close_at_tolerance( fraction_tolerance_t<ToleranceBaseType> tolerance, |
|---|
| 155 | floating_point_comparison_type fpc_type = FPC_STRONG ) |
|---|
| 156 | : p_fraction_tolerance( tt_detail::fpt_abs( tolerance.m_value ) ) |
|---|
| 157 | , p_strong_or_weak( fpc_type == FPC_STRONG ) |
|---|
| 158 | {} |
|---|
| 159 | |
|---|
| 160 | bool operator()( FPT left, FPT right ) const |
|---|
| 161 | { |
|---|
| 162 | FPT diff = tt_detail::fpt_abs( left - right ); |
|---|
| 163 | FPT d1 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( right ) ); |
|---|
| 164 | FPT d2 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( left ) ); |
|---|
| 165 | |
|---|
| 166 | return p_strong_or_weak |
|---|
| 167 | ? (d1 <= p_fraction_tolerance && d2 <= p_fraction_tolerance) |
|---|
| 168 | : (d1 <= p_fraction_tolerance || d2 <= p_fraction_tolerance); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | // Public properties |
|---|
| 172 | readonly_property<FPT> p_fraction_tolerance; |
|---|
| 173 | readonly_property<bool> p_strong_or_weak; |
|---|
| 174 | }; |
|---|
| 175 | |
|---|
| 176 | //____________________________________________________________________________// |
|---|
| 177 | |
|---|
| 178 | // ************************************************************************** // |
|---|
| 179 | // ************** check_is_close ************** // |
|---|
| 180 | // ************************************************************************** // |
|---|
| 181 | |
|---|
| 182 | struct BOOST_TEST_DECL check_is_close_t { |
|---|
| 183 | // Public typedefs |
|---|
| 184 | typedef bool result_type; |
|---|
| 185 | |
|---|
| 186 | template<typename FPT, typename ToleranceBaseType> |
|---|
| 187 | bool |
|---|
| 188 | operator()( FPT left, FPT right, percent_tolerance_t<ToleranceBaseType> tolerance, |
|---|
| 189 | floating_point_comparison_type fpc_type = FPC_STRONG ) |
|---|
| 190 | { |
|---|
| 191 | close_at_tolerance<FPT> pred( tolerance, fpc_type ); |
|---|
| 192 | |
|---|
| 193 | return pred( left, right ); |
|---|
| 194 | } |
|---|
| 195 | template<typename FPT, typename ToleranceBaseType> |
|---|
| 196 | bool |
|---|
| 197 | operator()( FPT left, FPT right, fraction_tolerance_t<ToleranceBaseType> tolerance, |
|---|
| 198 | floating_point_comparison_type fpc_type = FPC_STRONG ) |
|---|
| 199 | { |
|---|
| 200 | close_at_tolerance<FPT> pred( tolerance, fpc_type ); |
|---|
| 201 | |
|---|
| 202 | return pred( left, right ); |
|---|
| 203 | } |
|---|
| 204 | }; |
|---|
| 205 | |
|---|
| 206 | namespace { |
|---|
| 207 | check_is_close_t check_is_close; |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | //____________________________________________________________________________// |
|---|
| 211 | |
|---|
| 212 | // ************************************************************************** // |
|---|
| 213 | // ************** check_is_small ************** // |
|---|
| 214 | // ************************************************************************** // |
|---|
| 215 | |
|---|
| 216 | struct BOOST_TEST_DECL check_is_small_t { |
|---|
| 217 | // Public typedefs |
|---|
| 218 | typedef bool result_type; |
|---|
| 219 | |
|---|
| 220 | template<typename FPT> |
|---|
| 221 | bool |
|---|
| 222 | operator()( FPT fpv, FPT tolerance ) |
|---|
| 223 | { |
|---|
| 224 | return tt_detail::fpt_abs( fpv ) < tt_detail::fpt_abs( tolerance ); |
|---|
| 225 | } |
|---|
| 226 | }; |
|---|
| 227 | |
|---|
| 228 | namespace { |
|---|
| 229 | check_is_small_t check_is_small; |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | //____________________________________________________________________________// |
|---|
| 233 | |
|---|
| 234 | } // namespace test_tools |
|---|
| 235 | |
|---|
| 236 | } // namespace boost |
|---|
| 237 | |
|---|
| 238 | //____________________________________________________________________________// |
|---|
| 239 | |
|---|
| 240 | #include <boost/test/detail/enable_warnings.hpp> |
|---|
| 241 | |
|---|
| 242 | // *************************************************************************** |
|---|
| 243 | // Revision History : |
|---|
| 244 | // |
|---|
| 245 | // $Log: floating_point_comparison.hpp,v $ |
|---|
| 246 | // Revision 1.26.2.2 2006/11/30 14:41:21 jhunold |
|---|
| 247 | // Merge from HEAD: Remove unnecessary export makro. |
|---|
| 248 | // |
|---|
| 249 | // Revision 1.26.2.1 2006/05/22 17:39:12 johnmaddock |
|---|
| 250 | // Fix min/max guidelines violation. |
|---|
| 251 | // |
|---|
| 252 | // Revision 1.26 2006/03/16 07:31:06 vladimir_prus |
|---|
| 253 | // Fix compile error on MSVC due to max and min being defined as macros. |
|---|
| 254 | // |
|---|
| 255 | // Revision 1.25 2006/03/13 18:28:25 rogeeff |
|---|
| 256 | // warnings eliminated |
|---|
| 257 | // |
|---|
| 258 | // Revision 1.24 2005/12/14 05:07:28 rogeeff |
|---|
| 259 | // introduced an ability to test on closeness based on either percentage dirven tolerance or fraction driven one |
|---|
| 260 | // |
|---|
| 261 | // Revision 1.23 2005/05/29 08:54:57 rogeeff |
|---|
| 262 | // allow bind usage |
|---|
| 263 | // |
|---|
| 264 | // Revision 1.22 2005/02/21 10:21:40 rogeeff |
|---|
| 265 | // check_is_small implemented |
|---|
| 266 | // check functions implemented as function objects |
|---|
| 267 | // |
|---|
| 268 | // Revision 1.21 2005/02/20 08:27:05 rogeeff |
|---|
| 269 | // This a major update for Boost.Test framework. See release docs for complete list of fixes/updates |
|---|
| 270 | // |
|---|
| 271 | // Revision 1.20 2005/02/01 06:40:06 rogeeff |
|---|
| 272 | // copyright update |
|---|
| 273 | // old log entries removed |
|---|
| 274 | // minor stilistic changes |
|---|
| 275 | // depricated tools removed |
|---|
| 276 | // |
|---|
| 277 | // Revision 1.19 2005/01/22 19:22:12 rogeeff |
|---|
| 278 | // implementation moved into headers section to eliminate dependency of included/minimal component on src directory |
|---|
| 279 | // |
|---|
| 280 | // *************************************************************************** |
|---|
| 281 | |
|---|
| 282 | #endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER |
|---|
| 283 | |
|---|