2

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

Jignesh
  • 555
  • 1
  • 8
  • 18
  • 1
    “after some googling I found this nice simple way to round a no” The way you found does not work. http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1 – Pascal Cuoq Mar 02 '14 at 20:06
  • actually, I just saw that there is a std function roundl, which takes long double as input, and thats exactly what I wanted :) – Jignesh Mar 03 '14 at 03:50

1 Answers1

2

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.

Nicolas Defranoux
  • 2,646
  • 1
  • 10
  • 13
  • but why was it necessary to add in std namespace, I mean why not in cmath directly? – Jignesh Mar 02 '14 at 18:39
  • 1
    When they created the C++ namespaces they placed new stuff there. C still exists and is still used (e.g. for embedded systems or Linux kernel) and C++ comes as a layer on the top of C that must not change the behavior of C programs. Having namespaces allow to avoid any conflict with old methods (even if these old methods should be in museums rather than in our .h files). – Nicolas Defranoux Mar 02 '14 at 18:43