Question

I am trying to use the fmod function but I am not getting the results I am expecting.

Était-ce utile?

La solution

It actually returns 9.299999999999994 due to floating point imprecision. Neither 55.8 or 9.3 can be exactly represented as a base 2 floating point number.

It's a very common problem. One good reference is What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Autres conseils

Like most decimal fractions, these numbers can't be represented exactly as binary floating point values. Assuming the most common implementation of double, the actual values are approximately:

55.799999999999997158

and:

9.3000000000000007105

These do not divide exactly, and the result of fmod is approximately:

9.2999999999999936051

which is rounded to 9.3 when displayed to a small number of decimal places.

These values were produced with the following C++ program:

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    std::cout << std::setprecision(20);

    double a = 55.8;
    double b = 9.3;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << fmod(a,b) << std::endl;
}

The fact that you're expecting it to be somewhere near 6 implies that your problem isn't that you don't understand rounding, but that you don't know what fmod actually does.

fmod is the remainder of the division, not the quotient. That is, it's the amount left over after subtracting out an integral number of copies of the divisor. In mathematical terms, a = q*b + r, where q = int(a/b), and r = fmod(a, b).

If a and b were exactly 55.8 and 9.3, a/b would be exactly 6, and the remainder 0. So, it's perfectly reasonable for you to expect 0 as a result, and on some platforms that might be what you actually get.

However, on most platforms, the closest approximations possible to 55.8 and 9.3 are about 55.799999999999997158 and 9.3000000000000007105 (see Mark Ransom's answer for why), which means the quotient is 5.999999999999999, which means the integral part of the quotient is 5, which means the remainder is 55.799999999999997158 - 9.3000000000000007105 * 5 = 9.299999999999997, which is displayed as 9.3.

If you think about it, this makes sense. If the right remainder is 0, a small rounding error can't make the remainder 1 or 6; really all that's possible is something very near 0 or something very near 9.3. (If it helps, think about modulo 9.3 arithmetic, where 0 and 9.3 are the same number.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top