6

In the below example app I calculate the floating point remainder from dividing 953 by 0.1, using std::fmod

What I was expecting is that since 953.0 / 0.1 == 9530, that std::fmod(953, 0.1) == 0

I'm getting 0.1 - why is this the case?

Note that with std::remainder I get the correct result.

That is:

std::fmod     (953, 0.1) == 0.1 // unexpected
std::remainder(953, 0.1) == 0   // expected

Difference between the two functions:

According to cppreference.com

  • std::fmod calculates the following:

exactly the value x - n*y, where n is x/y with its fractional part truncated

  • std::remainder calculates the following:

exactly the value x - n*y, where n is the integral value nearest the exact value x/y

Given my inputs I would expect both functions to have the same output. Why is this not the case?

Exemplar app:

#include <iostream>
#include <cmath>

bool is_zero(double in)
{
    return std::fabs(in) < 0.0000001;
}

int main()
{
    double numerator   = 953;
    double denominator = 0.1;

    double quotient = numerator / denominator;
    double fmod     = std::fmod     (numerator, denominator);
    double rem      = std::remainder(numerator, denominator);

    if (is_zero(fmod))
        fmod = 0;
    if (is_zero(rem))
        rem = 0;

    std::cout << "quotient: " << quotient << ", fmod: " << fmod << ", rem: " << rem << std::endl;
    return 0;
}

Output:

quotient: 9530, fmod: 0.1, rem: 0
Community
  • 1
  • 1
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213

2 Answers2

12

Because they are different functions.

std::remainder(x, y) calculates IEEE remainder which is x - (round(x/y)*y) where round is rounding half to even (so in particular round(1.0/2.0) == 0)

std::fmod(x, y) calculates x - trunc(x/y)*y. When you divide 953 by 0.1 you may get a number slightly smaller than 9530, so truncation gives 9529. So as the result you get 953.0 - 952.9 = 0.1

Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • 2
    What he doesn't understand is why `fmod` returns 0.1 -- and you didn't explain that. – David Schwartz Oct 22 '14 at 23:58
  • "std::remainder(x,y) calculates x-(round(x/y)*y)" - Does it actually? For instance, std::remainder(1.0,2.0) is 1.0, whereas (1.0-round(1.0/2.0)*2.0) is -1.0. This is with g++ 7.3.0. – user2258552 Aug 01 '18 at 22:08
  • 1
    @user2258552 `round(1.0/2.0) == 0` by IEEE definition (quite weird) - I've edited my answer to clarify that. Thanks for pointing out. – Anton Savin Aug 01 '18 at 23:33
11

Welcome to floating point math. Here's what happens: One tenth cannot be represented exactly in binary, just as one third cannot be represented exactly in decimal. As a result, the division produces a result slightly below 9530. The floor operation produces the integer 9529 instead of 9530. And then this leaves 0.1 left over.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Then why does `int(953/.1) == 9530`? If your assertion is correct, shouldn't that be truncated to `9529` too? – Baum mit Augen Oct 10 '16 at 21:32
  • a better answer, in my opinion, is at http://stackoverflow.com/a/39966752/364084. It explains the discrepancies between the expected result if we go by the documentation of fmod() and the actual result. And it is due to the usage of remainder() inside fmod() implementation. – umbersar Oct 10 '16 at 22:34