File indexing completed on 2025-01-18 09:52:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
0013 #define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
0014
0015
0016 #include <boost/test/detail/global_typedef.hpp>
0017 #include <boost/test/tools/assertion_result.hpp>
0018
0019
0020 #include <boost/limits.hpp> // for std::numeric_limits
0021 #include <boost/static_assert.hpp>
0022 #include <boost/assert.hpp>
0023 #include <boost/mpl/bool.hpp>
0024 #include <boost/type_traits/is_floating_point.hpp>
0025 #include <boost/type_traits/is_array.hpp>
0026 #include <boost/type_traits/is_reference.hpp>
0027 #include <boost/type_traits/is_void.hpp>
0028 #include <boost/type_traits/conditional.hpp>
0029 #include <boost/utility/enable_if.hpp>
0030
0031
0032 #include <iosfwd>
0033
0034 #include <boost/test/detail/suppress_warnings.hpp>
0035
0036
0037
0038 namespace boost {
0039 namespace math {
0040 namespace fpc {
0041
0042
0043
0044
0045
0046
0047
0048
0049 template <typename T, bool enabled>
0050 struct tolerance_based_delegate;
0051
0052 template <typename T>
0053 struct tolerance_based_delegate<T, false> : mpl::false_ {};
0054
0055
0056 template<typename T>
0057 class is_abstract_class_or_function
0058 {
0059 typedef char (&Two)[2];
0060 template<typename U> static char test(U(*)[1]);
0061 template<typename U> static Two test(...);
0062
0063 public:
0064 static const bool value =
0065 !is_reference<T>::value
0066 && !is_void<T>::value
0067 && (sizeof(test<T>(0)) == sizeof(Two));
0068 };
0069
0070
0071
0072 template <typename T>
0073 struct tolerance_based_delegate<T, true>
0074 : mpl::bool_<
0075 is_floating_point<T>::value ||
0076 (!std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_exact)>
0077 {};
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 template <typename T>
0090 struct tolerance_based : tolerance_based_delegate<T, !is_array<T>::value && !is_abstract_class_or_function<T>::value>::type {};
0091
0092
0093
0094
0095
0096
0097 enum strength {
0098 FPC_STRONG,
0099 FPC_WEAK
0100 };
0101
0102
0103
0104
0105
0106
0107 template<typename FPT>
0108 struct percent_tolerance_t {
0109 explicit percent_tolerance_t( FPT v ) : m_value( v ) {}
0110
0111 FPT m_value;
0112 };
0113
0114
0115
0116 template<typename FPT>
0117 inline std::ostream& operator<<( std::ostream& out, percent_tolerance_t<FPT> t )
0118 {
0119 return out << t.m_value;
0120 }
0121
0122
0123
0124 template<typename FPT>
0125 inline percent_tolerance_t<FPT>
0126 percent_tolerance( FPT v )
0127 {
0128 return percent_tolerance_t<FPT>( v );
0129 }
0130
0131
0132
0133
0134
0135
0136
0137 namespace fpc_detail {
0138
0139
0140 template<typename FPT>
0141 inline FPT
0142 fpt_abs( FPT fpv )
0143 {
0144 return fpv < static_cast<FPT>(0) ? -fpv : fpv;
0145 }
0146
0147
0148
0149 template<typename FPT>
0150 struct fpt_specialized_limits
0151 {
0152 static FPT min_value() { return (std::numeric_limits<FPT>::min)(); }
0153 static FPT max_value() { return (std::numeric_limits<FPT>::max)(); }
0154 };
0155
0156 template<typename FPT>
0157 struct fpt_non_specialized_limits
0158 {
0159 static FPT min_value() { return static_cast<FPT>(0); }
0160 static FPT max_value() { return static_cast<FPT>(1000000); }
0161 };
0162
0163 template<typename FPT>
0164 struct fpt_limits : boost::conditional<std::numeric_limits<FPT>::is_specialized,
0165 fpt_specialized_limits<FPT>,
0166 fpt_non_specialized_limits<FPT>
0167 >::type
0168 {};
0169
0170
0171
0172
0173 template<typename FPT>
0174 inline FPT
0175 safe_fpt_division( FPT f1, FPT f2 )
0176 {
0177
0178 if( (f2 < static_cast<FPT>(1)) && (f1 > f2*fpt_limits<FPT>::max_value()) )
0179 return fpt_limits<FPT>::max_value();
0180
0181
0182 if( (fpt_abs(f1) <= fpt_limits<FPT>::min_value()) ||
0183 ((f2 > static_cast<FPT>(1)) && (f1 < f2*fpt_limits<FPT>::min_value())) )
0184 return static_cast<FPT>(0);
0185
0186 return f1/f2;
0187 }
0188
0189
0190
0191 template<typename FPT, typename ToleranceType>
0192 inline FPT
0193 fraction_tolerance( ToleranceType tolerance )
0194 {
0195 return static_cast<FPT>(tolerance);
0196 }
0197
0198
0199
0200 template<typename FPT2, typename FPT>
0201 inline FPT2
0202 fraction_tolerance( percent_tolerance_t<FPT> tolerance )
0203 {
0204 return FPT2(tolerance.m_value)*FPT2(0.01);
0205 }
0206
0207
0208
0209 }
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 template<typename FPT>
0226 class close_at_tolerance {
0227 public:
0228
0229 typedef bool result_type;
0230
0231
0232 template<typename ToleranceType>
0233 explicit close_at_tolerance( ToleranceType tolerance, fpc::strength fpc_strength = FPC_STRONG )
0234 : m_fraction_tolerance( fpc_detail::fraction_tolerance<FPT>( tolerance ) )
0235 , m_strength( fpc_strength )
0236 , m_tested_rel_diff( 0 )
0237 {
0238 BOOST_ASSERT_MSG( m_fraction_tolerance >= FPT(0), "tolerance must not be negative!" );
0239 }
0240
0241
0242
0243 FPT fraction_tolerance() const { return m_fraction_tolerance; }
0244
0245
0246 fpc::strength strength() const { return m_strength; }
0247
0248
0249 FPT tested_rel_diff() const { return m_tested_rel_diff; }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 bool operator()( FPT left, FPT right ) const
0263 {
0264 FPT diff = fpc_detail::fpt_abs<FPT>( left - right );
0265 FPT fraction_of_right = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( right ) );
0266 FPT fraction_of_left = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( left ) );
0267
0268 FPT max_rel_diff = (std::max)( fraction_of_left, fraction_of_right );
0269 FPT min_rel_diff = (std::min)( fraction_of_left, fraction_of_right );
0270
0271 m_tested_rel_diff = m_strength == FPC_STRONG ? max_rel_diff : min_rel_diff;
0272
0273 return m_tested_rel_diff <= m_fraction_tolerance;
0274 }
0275
0276 private:
0277
0278 FPT m_fraction_tolerance;
0279 fpc::strength m_strength;
0280 mutable FPT m_tested_rel_diff;
0281 };
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293 template<typename FPT>
0294 class small_with_tolerance {
0295 public:
0296
0297 typedef bool result_type;
0298
0299
0300 explicit small_with_tolerance( FPT tolerance )
0301 : m_tolerance( tolerance )
0302 {
0303 BOOST_ASSERT( m_tolerance >= FPT(0) );
0304 }
0305
0306
0307 bool operator()( FPT fpv ) const
0308 {
0309 return fpc::fpc_detail::fpt_abs( fpv ) <= m_tolerance;
0310 }
0311
0312 private:
0313
0314 FPT m_tolerance;
0315 };
0316
0317
0318
0319
0320
0321 template<typename FPT>
0322 inline bool
0323 is_small( FPT fpv, FPT tolerance )
0324 {
0325 return small_with_tolerance<FPT>( tolerance )( fpv );
0326 }
0327
0328
0329
0330 }
0331 }
0332 }
0333
0334 #include <boost/test/detail/enable_warnings.hpp>
0335
0336 #endif