2 + 2 = 5(*)
(for some floating-precision values of 2)
This problem frequently arises when we think of"floating point" as a way to increase precision. Then we run afoul of the "floating" part, which means there is no guarantee of which numbers can be represented.
So while we might easily be able to represent "1.0, -1.0, 0.1, -0.1" as we get to larger numbers we start to see approximations - or we should, except we often hide them by truncating the numbers for display.
As a result, we might think the computer is storing "0.003" but it may instead be storing "0.0033333333334".
What happens if you perform "0.0003 - 0.0002"? We expect .0001, but the actual values being stored might be more like "0.00033" - "0.00029" which yields "0.000004", or the closest representable value, which might be 0, or it might be "0.000006".
With current floating point math operations, it is not guaranteed that (a / b) * b == a.
#include <stdio.h>
// defeat inline optimizations of 'a / b * b' to 'a'
extern double bodge(int base, int divisor) {
return static_cast<double>(base) / static_cast<double>(divisor);
}
int main() {
int errors = 0;
for (int b = 1; b < 100; ++b) {
for (int d = 1; d < 100; ++d) {
// b / d * d ... should == b
double res = bodge(b, d) * static_cast<double>(d);
// but it doesn't always
if (res != static_cast<double>(b))
++errors;
}
}
printf("errors: %d\n", errors);
}
ideone reports 599 instances where (b * d) / d != b using just the 10,000 combinations of 1 <= b <= 100 and 1 <= d <= 100 .
The solution described in the FAQ is essentially to apply a granularity constraint - to test if (a == b +/- epsilon)
.
An alternative approach is to avoid the problem entirely by using fixed point precision or by using your desired granularity as the base unit for your storage. E.g. if you want times stored with nanosecond precision, use nanoseconds as your unit of storage.
C++11 introduced std::ratio as the basis for fixed-point conversions between different time units.