The problem you see is that the version of fmod you use matches the implementation defined in cppreference
double fmod(double x, double y) { double result = std::remainder(std::fabs(x), (y = std::fabs(y))); if (std::signbit(result)) result += y; return std::copysign(result, x); }
std::remainder calculates a very small result, almost zero (-5.55112e-17 when using 1 and 0.1 for me, -1.11022e-16 for 2 and 0.2). However, it is important that the result is negative, which means std::signbit returns true, as a result of which y added to the result, effectively making the result equal to y .
Note that the std::fmod documentation std::fmod nothing about using std::remainder :
The remainder of the x / y division floating point calculated by this function is exactly the value x - n * y, where n is x / y with the abbreviated fractional part.
So, if you calculate the value yourself, you will get zero (even if you use std::round for the result instead of a pure integer truncation)
We see similar problems when x is 2 and y is 0.2
double x = 2; double y = .2; int n = static_cast<int>(x/y); double result = x - n*y; std::cout << "Manual: " << result << std::endl; std::cout << "fmod: " << std::fmod(x,y) << std::endl;
Exit ( gcc demo )
Manually: 0
fmod: 0.2
However, the problem does not apply only to gcc; I also see this in MSVC and clang. Clang sometimes has a different behavior if you use float instead of double .
This really small negative value from std::remainder stems from the fact that neither 0.1 nor 0.2 can be represented exactly in floating point math. If you change x and y to, say 2 and 0.25, then everything will be fine.