output of fmod function c++
Asked Answered
I

1

5

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 would have expected the fmod() result to be near 0 but what i get is .0999999999. It is a significant difference. The result of remainder() still seem acceptable. Code could be tried at http://ideone.com/9wBlva

Why this significant difference for fmod() result?

Itinerancy answered 10/10, 2016 at 20:25 Comment(14)
C++ and C Arent the same langaugeParaboloid
If that does not answer your question on its own, read the docs. fmod and remainder don't do the same thing, so different results are to be expected.Aphis
@Paraboloid u get similar results ideone.com/rLyS2tItinerancy
@BaummitAugen: I'm still a little confused. The documentation on fmod states that "The floating-point remainder of the division operation x/y calculated by this function is exactly the value x - n*y, where n is x/y with its fractional part truncated.", but if I explicitly compute that myself, I get a result of 0 while fmod still returns 0.1. Example. If I use float instead of double, the value comes out as expected DemoFrontward
@wanderer Just because a program happens to work in both a C++ Compiler and a C Compiler doesn't make it so , that C++ And C Are the same language.Paraboloid
@Paraboloid The example i posted for C is C code. I should consider it end of this discussion.Itinerancy
I mean, the underlying diagnosis of my dupe vote is most likely still correct because .1 cannot be represented exactly in C++ doubles (IEEE-754 doubles, to be more precise), but I guess this output could need some more explanation.Aphis
@BaummitAugen I see similar issues when using 2 and 0.2. I can't help but feel there's something I'm not getting, so I'm afraid of voting to reopen.Frontward
@wanderer Two things , first of all there is no concept of namespaces in C, Second of all Do Not Use using namespace std; !! . There is a reason why your question is tagged C++ , please think before tagging , so you dont spam other tags. Thankyou!Paraboloid
@amanuel2: What do you mean there is no concept of namespaces in C++? We use them all the time. Second, for use in a small toy example like this it's no problem, though not recommended.Frontward
@Frontward I Meant to type C . MistypeParaboloid
@Frontward Unsurprisingly, the problem goes away when using 1, .25 which are represented exactly (Live). Now the question is why int(1/.1) yields 10 instead of 9.Aphis
@Frontward As of the time of your comment, I already reopened it. ;)Aphis
The value 0.1 cannot be represented exactly in binary floating-point. The actual value of h is most likely 0.1000000000000000055511151231257827021181583404541015625, which can be represented exactly.Barcot
F
4

The problem you're seeing is that the version of fmod you're using appears to follow the implementation defined at 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 computes a very very small result, nearly zero (-5.55112e-17 when using 1 and 0.1 for me, -1.11022e-16 for 2 and 0.2). However, what's important is that the result is negative, which means std::signbit returns true, causing y to get added to the result, effectively making the result equal to y.

Note that the documentation of std::fmod doesn't say anything about using std::remainder:

The floating-point remainder of the division operation x/y calculated by this function is exactly the value x - n*y, where n is x/y with its fractional part truncated.

So if you compute the value yourself, you do end up with zero (even if you use std::round on the result instead of 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;

Output (gcc demo) is

Manual: 0
fmod: 0.2

However the problem is not relegated to only gcc; I also see it in MSVC and clang. In clang there is sometimes different behavior if one uses float instead of double.

This really small negative value from std::remainder comes 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 all is well.

Frontward answered 10/10, 2016 at 21:6 Comment(12)
For fmod: "is exactly the value x - n*y, where n is x/y with its fractional part truncated." And by int(x/h) == 10, n should be 10 and thus fmod(x,h) == 1 - 10 * .1 which should be almost 0. So far the stuff in your answer is not enough to explain this.Aphis
I just found a similar question asked here..https://mcmap.net/q/1591416/-why-am-i-getting-a-different-result-from-std-fmod-and-std-remainder/364084.Itinerancy
@Frontward I am still working out the result manually as per this explanation. If it works out, I will mark it as the answerItinerancy
@wanderer Now that looks like an actual dupe.Aphis
@BaummitAugen yes it does. I will try to manually verify to see if it does answer the question.Itinerancy
@BaummitAugen: I tried to make it clear that the problem stemmed from std::remainder to compute fmod returning a negative value. Following the logic of the fmod implementation, it's no wonder that the result is basically yFrontward
@Frontward I still don't see how that addresses my point with the truncating assignment yielding 10.Aphis
@Frontward yes I found the explanation of std::remainder returning a -ve value along with the code for fmod implementation helpfulItinerancy
@wanderer The important part here is whether or not the question itself is a dupe, less whether or not the answers there are great (which they probably aren't). If we need more/better answers, I think we should use bounties / upvotes on the original.Aphis
@BaummitAugen: Oh I totally agree. I didn't try to justify the behavior as correct. By the documentation of fmod, this behavior is a bug in my opinion. It looks like the cause of that is both by using std::remainder and by perhaps incompletely handling a negative result.Frontward
I am marking this as the answer and it is in my opinion a better answer than ones on https://mcmap.net/q/1591416/-why-am-i-getting-a-different-result-from-std-fmod-and-std-remainder/364084. It points out that the documentation of fmod() does not agree with its internal implementation due to its use of std::remainder(not mentioned in documentationn) and if we did infact tried to do what the description of fmod() said, we would have gotten 0(the expected result). And since fmod is using std::remainder internally and expecting the behaviour of remainder() to known to the implementers of fmod(), this case could have been handled in a better manner.Itinerancy
As this seems to be the still current behaviour of clang and gcc, we can conclude that fmod is basically useless if the second parameter almost evenly divides the first, right? So you can never use it to determine this fact basically. At least for values in this range discussed here.Williford

© 2022 - 2024 — McMap. All rights reserved.