1[/ 2 / Copyright (c) 2003-2015 Boost.Test contributors 3 / 4 / Distributed under the Boost Software License, Version 1.0. (See accompanying 5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 /] 7 8 9[/ ################################################ ] 10[section:floating_point Floating point comparison] 11 12Unless specified otherwise, when a value of floating-point type is compared inside a __BOOST_TEST__ assertion, 13operators `==`, `!=` , `<` etc. defined for this type are used. However for floating point type, in most cases what is needed is not an ['exact] 14equality (or inequality), but a verification that two numbers are ['sufficiently close] or ['sufficiently different]. For that purpose, a [*tolerance] parameter 15that will instruct the framework what is considered ['sufficiently close] needs to provided. 16 17[note 18 How the tolerance parameter is processed in detail is described [link boost_test.testing_tools.extended_comparison.floating_point.floating_points_comparison_impl here]. 19] 20 21[h4 Test-unit tolerance] 22It is possible to define a per-[link ref_test_unit test unit] tolerance for a given floating point type by using 23[link boost_test.tests_organization.decorators decorator] __decorator_tolerance__: 24 25[bt_example tolerance_01..specifying tolerance per test case..run-fail] 26 27[h4 Assertion tolerance] 28It is possible to specify floating point comparison tolerance per single assertion, by providing the ['manipulator] [funcref boost::test_tools::tolerance] 29as the second argument to __BOOST_TEST__: 30 31[bt_example tolerance_02..specifying tolerance per assertion..run-fail] 32 33[caution Manipulators requires a compiler that supports variadic macros, `auto` for type deduction 34 and `decltype`. These are C++11 features, but are also available on some pre-C++11 compilers. On compilers that are 35 lacking these features, resort to defining tolerance per test unit or to compatibility test assertions: __BOOST_CHECK_CLOSE__ and __BOOST_CHECK_SMALL__.] 36 37[h4 Tolerance expressed in percentage] 38It is possible to specify the tolerance as percentage. At test unit level, the decorator syntax is: 39 40``` 41* boost::unit_test::tolerance( boost::test_tools::fpc::percent_tolerance(2.0) ) 42// equivalent to: boost::unit_test::tolerance( 2.0 / 100 ) 43``` 44 45At assertion level, the manipulator syntax is: 46 47``` 482.0% boost::test_tools::tolerance() 49boost::test_tools::tolerance( boost::test_tools::fpc::percent_tolerance(2.0) ) 50// both equivalent to: boost::test_tools::tolerance( 2.0 / 100 ) 51``` 52 53[h4 Type of the tolerance] 54Manipulator `tolerance` specifies the tolerance only for a single floating-point type. This type is deduced from form 55the numeric value passed along the manipulator: 56 57[table 58[[expression][semantics]] 59[[`tolerance(0.5)`][tolerance for type `double` changed to 0.5]] 60[[`tolerance(float(0.5))`][tolerance for type `float` changed to 0.5]] 61[[`tolerance(0.5f)`][tolerance for type `float` changed to 0.5]] 62[[`tolerance(0.5L)`][tolerance for type `long double` changed to 0.5]] 63[[`tolerance(Decimal("0.5"))`][tolerance for a user-defined type `Decimal` changed to the supplied value]] 64[[`5.0% tolerance()`][tolerance for type `double` changed to 0.05 (`5.0 / 100`)]] 65[[`5.0f% tolerance()`][tolerance for type `float` changed to 0.05]] 66[[`Decimal("5.0")% tolerance()`][tolerance for type `Decimal` changed to value `(Decimal("5.0") / 100)`]] 67] 68 69This is also the case for decorator `tolerance`. In the case of the decorator however, it is possible to apply multiple 70decorators `tolerance` defining the tolerance for different types. 71 72When values of two different floating point types `T` and `U` are compared, __BOOST_TEST__ uses the tolerance 73specified for type `boost::common_type<T, U>::type`. For instance, when setting a tolerance for mixed `float`-to-`double` comparison, 74the tolerance for type `double` needs to be set. 75 76Given two floating point types `T` and `U` and their common type `C`, the tolerance specified for type `C` is applied only when 77types `T` and `U` appear as sub-expressions of the full expression inside assertion __BOOST_TEST__. It is not applied when 78`T` and `U` are compared inside a function invoked during the evaluation of the expression: 79 80[bt_example tolerance_05..tolerance applied to different types..run-fail] 81 82[h4 Type promotion of the operands] 83Given two types `T` and `U` being compared inside an assertion __BOOST_TEST__, tolerance based comparison is invoked 84 85# whenever the types `T` and `U` are both [link boost_test.testing_tools.extended_comparison.floating_point.customizing_for_tolerance tolerance based] types 86# whenever `T` is /tolerance/ based and `U` is /arithmetic/, in the sense that `std::numeric_limits<U>::value` evaluates to `true` (or the other way round) 87 88In all cases, the type of the tolerance is deduced as `boost::common_type<T, U>::type`, and both type may be cast to this tolerance type. 89 90[note This behavior has been introduced in Boost 1.70 / __UTF__ [link ref_CHANGE_LOG_3_10 3.10]. Previously tolerance based comparison was used only when the type of the two 91 operands were tolerance based types, which was silently ignoring the tolerance for expressions such as 92 93 `` 94 double x = 1E-9; 95 BOOST_TEST(x == 0); // U is int 96 `` 97] 98 99[bt_example tolerance_06..operands type promotion..run-fail] 100 101[h4 Other relational operators] 102 103Finally, note that comparisons for tolerance are also applied to `operator<` with semantics ['less by more than some tolerance], 104and other relational operators. Also, the tolerance-based comparisons are involved when a more complicated expression tree is 105processed within the assertion body. The section on 106[link boost_test.testing_tools.extended_comparison.floating_point.floating_points_comparison_impl.tolerance_in_operator relational operators] 107defines how `operator<` relates to tolerance. 108 109[bt_example tolerance_03..tolerance applied in more complex expressions..run-fail] 110 111 112 113 114[/############################################################################] 115 116[section:customizing_for_tolerance Enabling tolerance for user-defined types] 117 118The __UTF__ recognizes that a given type `T` is suitable for tolerance-based comparisons using the expression 119[classref boost::math::fpc::tolerance_based]`<T>::value`. This meta-function already returns `true` for built-in 120floating-point types as well as any other types that match the following compile-time expression: 121 122``` 123boost::is_floating_point<T>::value || 124 ( std::numeric_limits<T>::is_specialized && 125 !std::numeric_limits<T>::is_integer && 126 !std::numeric_limits<T>::is_exact) 127``` 128 129If you require your type to also participate in tolerance-based comparisons, regardless of the above expression, 130you can just specialize [classref boost::math::fpc::tolerance_based] for your type directly, and derive it from 131`boost::true_type`. Your type does not even have to be a floating-point type provided that it models concept 132[link boost_test.testing_tools.extended_comparison.floating_point.customizing_for_tolerance.concept_tolerance_based `ToleranceCompatible`]. 133 134[bt_example tolerance_04..adapting user-defined types for tolerance-based comparison..run-fail] 135 136[h3:concept_tolerance_based Concept `ToleranceCompatible`] 137 138[h4 Refinement of] 139 140[@https://en.cppreference.com/w/cpp/named_req/MoveConstructible `MoveConstructible`], 141[@https://en.cppreference.com/w/cpp/named_req/EqualityComparable `EqualityComparable`], 142[@https://en.cppreference.com/w/cpp/named_req/LessThanComparable `LessThanComparable`] 143 144[h4 Notation] 145 146[table 147 [[][]] 148 [[`T`][A type that is a model of `ToleranceCompatible`]] 149 [[`x`, `y`][objects of type `T`]] 150 [[`i`, `j`][objects of type `int`]] 151] 152 153[h4 Valid expressions] 154 155[table 156 [[Name][Expression][Return type]] 157 [[Conversion from `int`][`T j = i;`][]] 158 [[Addition][`x + y`][`T`]] 159 [[Subtraction][`x - y`][`T`]] 160 [[Negation][`-x`][`T`]] 161 [[Multiplication][`x * y`[br]`x * i`][`T`]] 162 [[Division][`x / y`[br]`x / i`][`T`]] 163 [[Mixed equality][`x == i`[br]`x != i`][`bool`]] 164 [[Mixed ordering][`x < i`[br]`x > i`[br]`x <= i`[br]`x >= i`][`bool`]] 165] 166 167[h4 Invariants] 168 169[table 170 [[`T` and `int` consistency][`(x == T(i)) == (x == i)`[br]`(x != T(i)) == (x != i)`[br]`(x < T(i)) == (x < i)`[br]`(x > T(i)) == (x > i)`[br]`(x / T(i)) == (x / i)`[br]`(x * T(i)) == (x * i)`]] 171] 172 173[endsect] [/ customizing_for_tolerance] 174 175 176[/############################################################################################] 177 178[section:floating_points_comparison_impl Tolerance-based comparisons] 179 180 181Assertions in the __UTF__ use two kinds of comparison. For `u` being close to zero with absolute tolerance `eps`: 182 183`` 184 abs(u) <= eps; // (abs) 185`` 186 187For `u` and `v` being close with relative tolerance `eps`: 188 189``` 190 abs(u - v)/abs(u) <= eps 191&& abs(u - v)/abs(v) <= eps; // (rel) 192``` 193 194For rationale for choosing these formulae, see section __floating_points_testing_tools__. 195 196 197Assertion __BOOST_TEST__ (when comparing floating-point numbers) uses the following algorithm: 198 199* When either value `u` or `v` is zero, evaluates formula (abs) on the other value. 200* When the specified tolerance is zero, performs direct (native) comparison between `u` and `v`. 201* Otherwise, performs formula (rel) on `u` and `v`. 202 203[note Therefore in order to check if a number is close to zero with tolerance, you need to type: 204``` 205BOOST_TEST(v == T(0), tt::tolerance(eps)); 206```] 207 208The compatibility assertions __BOOST_LEVEL_CLOSE__ and __BOOST_LEVEL_CLOSE_FRACTION__ perform formula (rel). 209 210The compatibility assertion __BOOST_LEVEL_SMALL__ performs formula (abs). 211 212The __UTF__ also provides unary predicate [classref boost::math::fpc::small_with_tolerance `small_with_tolerance`] and binary predicate predicate 213[classref boost::math::fpc::close_at_tolerance `close_at_tolerance`] that implement formula (abs) and (rel) respectively. 214 215[h3 Tolerance in `operator<`] 216 217Tolerance-based computations also apply to `operator<` and other relational operators. The semantics are defined as follows: 218 219* ['less-at-tolerance] <==> ['strictly-less] and not ['close-at-tolerance] 220* ['greater-at-tolerance] <==> ['strictly-greater] and not ['close-at-tolerance] 221* ['less-or-equal-at-tolerance] <==> ['strictly-less] or ['close-at-tolerance] 222* ['greater-or-equal-at-tolerance] <==> ['strictly-greater] or ['close-at-tolerance] 223 224[note This implies that the exactly one of these: `u < v`, `u == v`, `u > v`, passes with __BOOST_TEST__ at any given tolerance.] 225[caution Relation ['less-at-tolerance] is not a ['Strict Weak Ordering] as it lacks the ['transitivity of the equivalence]; 226 using it as predicate in `std::map` or any order-based STL 227 algorithm would result in undefined behavior.] 228 229[endsect] [/ floating_points_comparison_impl] 230 231[/############################################################################################] 232 233[section:floating_points_comparison_theory Theory behind floating point comparisons] 234 235 236The following is the most obvious way to compare two floating-point values `u` and `v` for being close at a given absolute tolerance `epsilon`: 237 238[#equ1] 239`` 240 abs(u - v) <= epsilon; // (1) 241`` 242 243However, in many circumstances, this is not what we want. The same absolute tolerance value `0.01` may be too small to meaningfully compare 244two values of magnitude `10e12` and at the same time too little to meaningfully compare values of magnitude `10e-12`. For examples, see [link Squassabia]. 245 246We do not want to apply the same absolute tolerance for huge and tiny numbers. Instead, we would like to scale the `epsilon` with `u` and `v`. 247The __UTF__ implements floating-point comparison algorithm that is based on the solution presented in [link KnuthII Knuth]: 248 249[#equ2] 250`` 251 abs(u - v) <= epsilon * abs(u) 252&& abs(u - v) <= epsilon * abs(v)); // (2) 253`` 254 255defines a ['very close with tolerance `epsilon`] relationship between `u` and `v`, while 256 257[#equ3] 258`` 259 abs(u - v) <= epsilon * abs(u) 260|| abs(u - v) <= epsilon * abs(v); // (3) 261`` 262 263defines a ['close enough with tolerance `epsilon`] relationship between `u` and `v`. 264 265Both relationships are commutative but are not transitive. The relationship defined in 266[link equ2 (2)] is stronger that the relationship defined in [link equ3 (3)] since [link equ2 (2)] necessarily implies [link equ3 (3)]. 267 268The multiplication in the right side of inequalities may cause an unwanted underflow condition. To prevent this, 269the implementation is using modified version of [link equ2 (2)] and [link equ3 (3)], which scales the checked difference rather than `epsilon`: 270 271[#equ4] 272`` 273 abs(u - v)/abs(u) <= epsilon 274&& abs(u - v)/abs(v) <= epsilon; // (4) 275`` 276 277[#equ5] 278`` 279 abs(u - v)/abs(u) <= epsilon 280|| abs(u - v)/abs(v) <= epsilon; // (5) 281`` 282 283This way all underflow and overflow conditions can be guarded safely. The above however, will not work when `v` or `u` is zero. 284In such cases the solution is to resort to a different algorithm, e.g. [link equ1 (1)]. 285 286 287[h3 Tolerance selection considerations] 288 289In case of absence of domain specific requirements the value of tolerance can be chosen as a sum of the predicted 290upper limits for "relative rounding errors" of compared values. The "rounding" is the operation by which a real 291value 'x' is represented in a floating-point format with 'p' binary digits (bits) as the floating-point value [*X]. 292The "relative rounding error" is the difference between the real and the floating point values in relation to real 293value: `abs(x-X)/abs(x)`. The discrepancy between real and floating point value may be caused by several reasons: 294 295* Type promotion 296* Arithmetic operations 297* Conversion from a decimal presentation to a binary presentation 298* Non-arithmetic operation 299 300 301The first two operations proved to have a relative rounding error that does not exceed 302 303 half_epsilon = half of the 'machine epsilon value' 304 305for the appropriate floating point type `FPT` [footnote [*machine epsilon value] is represented by `std::numeric_limits<FPT>::epsilon()`]. 306Conversion to binary presentation, sadly, does not have such requirement. So we can't assume that `float(1.1)` is close 307to the real number `1.1` with tolerance `half_epsilon` for float (though for 11./10 we can). Non-arithmetic operations either do not have a 308predicted upper limit relative rounding errors. 309 310[note Note that both arithmetic and non-arithmetic operations might also 311produce others "non-rounding" errors, such as underflow/overflow, division-by-zero or "operation errors".] 312 313 314All theorems about the upper limit of a rounding error, including that of `half_epsilon`, refer only to 315the 'rounding' operation, nothing more. This means that the 'operation error', that is, the error incurred by the 316operation itself, besides rounding, isn't considered. In order for numerical software to be able to actually 317predict error bounds, the __IEEE754__ standard requires arithmetic operations to be 'correctly or exactly rounded'. 318That is, it is required that the internal computation of a given operation be such that the floating point result 319is the exact result rounded to the number of working bits. In other words, it is required that the computation used 320by the operation itself doesn't introduce any additional errors. The __IEEE754__ standard does not require same behavior 321from most non-arithmetic operation. The underflow/overflow and division-by-zero errors may cause rounding errors 322with unpredictable upper limits. 323 324At last be aware that `half_epsilon` rules are not transitive. In other words combination of two 325arithmetic operations may produce rounding error that significantly exceeds `2*half_epsilon`. All 326in all there are no generic rules on how to select the tolerance and users need to apply common sense and domain/ 327problem specific knowledge to decide on tolerance value. 328 329To simplify things in most usage cases latest version of algorithm below opted to use percentage values for 330tolerance specification (instead of fractions of related values). In other words now you use it to check that 331difference between two values does not exceed x percent. 332 333For more reading about floating-point comparison see references below. 334 335[h4 Bibliographic references] 336[variablelist Books 337 [ 338 [[#KnuthII]The art of computer programming (vol II)] 339 [Donald. E. Knuth, 1998, Addison-Wesley Longman, Inc., ISBN 0-201-89684-2, Addison-Wesley Professional; 3rd edition. 340 (The relevant equations are in §4.2.2, Eq. 36 and 37.)] 341 ] 342 [ 343 [Rounding near zero, in [@http://www.amazon.com/Advanced-Arithmetic-Digital-Computer-Kulisch/dp/3211838708 Advanced Arithmetic for the Digital Computer]] 344 [Ulrich W. Kulisch, 2002, Springer, Inc., ISBN 0-201-89684-2, Springer; 1st edition] 345 ] 346] 347 348[variablelist Periodicals 349 [ 350 [[#Squassabia][@https://adtmag.com/articles/2000/03/16/comparing-floats-how-to-determine-if-floating-quantities-are-close-enough-once-a-tolerance-has-been.aspx 351 Comparing Floats: How To Determine if Floating Quantities Are Close Enough Once a Tolerance Has Been Reached]] 352 [Alberto Squassabia, in C++ Report (March 2000)] 353 ] 354 355 [ 356 [The Journeyman's Shop: Trap Handlers, Sticky Bits, and Floating-Point Comparisons] 357 [Pete Becker, in C/C++ Users Journal (December 2000)] 358 ] 359] 360 361[variablelist Publications 362 [ 363 [[@http://dl.acm.org/citation.cfm?id=103163 364 What Every Computer Scientist Should Know About Floating-Point Arithmetic]] 365 [David Goldberg, pages 150-230, in Computing Surveys (March 1991), Association for Computing Machinery, Inc.] 366 ] 367 368 [ 369 [[@http://hal.archives-ouvertes.fr/docs/00/07/26/81/PDF/RR-3967.pdf From Rounding Error Estimation to Automatic Correction with Automatic Differentiation]] 370 [Philippe Langlois, Technical report, INRIA] 371 ] 372 373 [ 374 [[@http://www.cs.berkeley.edu/~wkahan/ 375 William Kahan home page]] 376 [Lots of information on floating point arithmetics.] 377 ] 378 379] 380 381[endsect] [/ theory] 382 383[endsect] [/ floating points] 384