First, fmod
is exact. Because it can: when x
and y
are floating-point numbers, the mathematical result of fmod(x,y)
can be represented exactly as a floating-point number.
Second, when you write 0.05
, you do not get exactly that number, because 5/100 on the other hand cannot be represented exactly as a floating-point number; and when you write +
, you do not get mathematical addition in general because the result of that mathematical addition cannot always be represented as a floating-point number(*).
Starting from 0.0 and repeatedly adding 0.05 will soon get you into inaccurate +
territory, because in binary, the best representation of 0.05 has many digits. As the sum gets larger, the last digits progressively have to be dropped. This is where the inaccuracy of +
comes from, and ultimately is the reason why fmod
does not give you the results you expect.
It wouldn't matter that 0.05
is not exactly 5/100 if repeatedly adding it to zero always was exact. But since the floating-point number 0.05
has many digits in binary (as opposed to decimal) and since some of these digits must be lost when computing multiples of 0.05
, the value you get for most multiples y
of 0.05
when computing fmod(y, 0.05)
is not zero but represents the difference between the mathematical multiplication of the appropriate integer by 0.05
and the approximation y
of that number.
(*) when the mathematical sum can be represented, the mathematical sum is what you get, but sometimes it just cannot.