Fmod c ++ function output

Given:

#include <iostream> #include <cmath> #include <limits> using namespace std; int main() { // your code goes here double h = .1; double x = 1; int nSteps = abs(x / h); double rem = fmod(x, h); cout<<"fmod output is "<<rem<<endl; if(abs(rem)<std::numeric_limits<double>::epsilon()) cout<<"fmod output is almost near 0"<<endl; rem = remainder(x,h); cout<<"remainder output is "<<rem<<endl; if(abs(rem)<std::numeric_limits<double>::epsilon()) cout<<"remainder output is almost near 0"<<endl; return 0; } 

Given int(x/h) == 10 , I expected the result of fmod() be close to 0, but I get .0999999999. This is a significant difference. The result of the remainder () is still acceptable. You can try the code at http://ideone.com/9wBlva

Why is this significant difference for the result of fmod ()?

+3
source share
1 answer

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.

+3
source

All Articles