Question

So I was recently trying a problem involving floating point arithmetic. Below is a snippet of that code.

#include<cstdio>
#include<cmath>
typedef unsigned long long ull;

int main(){
    long double n=1000000000,ans,ans1,ans2;
    ans = (n*n/48.0);

    ans1 = std::floor(ans+0.5); // Correct, got AC with this
    ans2 = floor(ans+0.5);      // Incorrect, got me 2 WA :(

    printf("%llu %llu\n",ull(ans1),ull(ans2));
}

Output:

20833333333333333 20833333333333332

In the problem I had to round the final ans. I first used round function from cmath, but got WA. Then after some googling I found this nice simple way to round a no

n = floor(n + 0.5);

But What surprises me is the weird behavior of floor function. It behaves differently when used with std namespace, and actually it behaves correctly only then.

My guess is that the floor function from std namespace returns a long double, while the normal floor function from cmath returns a double, hence the loss in precision.

So what I wonder is why these two functions are in different namespaces in cmath, wouldn't it be better if the compiler selected the appropriate floor function since I am passing it a 'long double', just like normal method overloading.

Thanks

Was it helpful?

Solution

The floor function from cmath is an heritage from C, it was here before C++ proposed a long double version of floor... Now we can't remove it as it's used, so the new one was created in std.

floor(ans+0.5) will cast (ans + 0.5) to a 'normal' double, hence the loss of precision.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top