Home > OS >  C long double precision difference with and without using namespace std;
C long double precision difference with and without using namespace std;

Time:06-12

I have stumbled upon quirky C behavior that I cannot explain.

I am trying to calculate the dimensions of an image when resizing it (maintaining its ratio) to fit as much screen as possible. The x, y variables are dimensions of the image and X, Y variables are dimensions of the screen. When the resulting dimensions are not integers, I need to round them using standard rules of mathematics.

This program for inputs 499999999999999999 10 1000000000000000000 19 gives the (incorrect) answer of 950000000000000000 19.

#include <iostream>
#include <cmath>
#include <algorithm>

int main(){
    long long x,y,X,Y;
    std::cin>>x>>y>>X>>Y;

    long double ratio = std::min((long double)X/x, (long double)Y/y);

    x= round(ratio*x);
    y= round(ratio*y);
    std::cout<<x<<" "<<y;

    return 0;
}

However, code below (only change is using namespace std; and removing std:: from main function body) gives the correct answer of 949999999999999998 19.

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

int main(){
    long long x,y,X,Y;
    cin>>x>>y>>X>>Y;

    long double ratio = min((long double)X/x, (long double)Y/y);

    x= round(ratio*x);
    y= round(ratio*y);
    cout<<x<<" "<<y;

    return 0;
}

I am using g (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 and compiling the program with g -std=c 17 -Wall -Wextra -Wshadow.

CodePudding user response:

In the first case you are calling double round(double) function from the global namespace, which is pulled in by the cmath header.

In the second case you are calling overloaded long double std::round(long double) function from the std namespace since your are using namespace std.

You can fix your code by adding std:: in front of round, as in:

#include <iostream>
#include <cmath>
#include <algorithm>

int main()
{
    long long x, y, X, Y;
    std::cin >> x >> y >> X >> Y;

    auto ratio = std::min((long double)X / x, (long double)Y / y);

    x = std::round(ratio * x); // <-- add std:: here
    y = std::round(ratio * y); // <-- add std:: here

    std::cout << x << " " << y;
    return 0;
}

UPDATE:

To explain what's going on here, when you call round in the first case, ratio * x is implicitly converted to double (which can only store 15 significant digits) before it is passed to the function.

This leads to loss of precision and an unexpected result in your case. No quirks.

  • Related