auto a{ 4.2 };
auto b{ 0.12 };
auto result = std::fmod(a, b);
if(result <= std::numeric_limits<double>::epsilon())
result = 0; // <-- This line isn't triggered
In this example, 4.2 is actually equal to 4.2000000000000002
due to double
imprecision.
Note that 4.2/0.12 = 35.
I would expect the output to be equal to std::numeric_limits<double>::epsilon()
. Instead, result is equal to 1.5 * std::numeric_limits<double>::epsilon()
.
Where does this 1.5 multiplier come from?
epsilon
? To verify why it is1.5*epsilon
, you can bring4.2
and0.12
into their binary form and then calculate the remainder.double
numbers in [1, 2) isepsilon
. The size of the steps between thedouble
numbers in [4, 8), in which 4.2 lies, is4*epsilon
. The size of the steps between thedouble
numbers in [.0625, .125), in which .12 lies, isepsilon/16
. Let’s call these steps,epsilon/16
,s
. Thedouble
nearest 4.2 is apparently24*s
away from the nearest multiple of thedouble
nearest .12.24*s
is1.5*epsilon
. That is where the 1.5 comes from.