我偶然发现了我无法解释的奇怪的 C++ 行为。
我试图在调整图像大小(保持其比例)以适应尽可能多的屏幕时计算图像的尺寸。x、y 变量是图像的尺寸,X、Y 变量是屏幕的尺寸。当结果维度不是整数时,我需要使用标准数学规则对它们进行舍入。
这个输入程序499999999999999999 10 1000000000000000000 19给出了(错误的)答案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 << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,下面的代码(仅更改并从函数体中using namespace std;删除)给出了正确的答案。std::main949999999999999998 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 << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0并编译该程序g++ -std=c++17 -Wall -Wextra -Wshadow。
在第一种情况下,您double round(double)从全局名称空间调用函数,该名称空间由cmath标头拉入。
long double std::round(long double)在第二种情况下,您从命名空间调用重载函数std,因为您是using namespace std.
std::您可以通过在 前面添加来修复代码round,如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
更新:
为了解释这里发生的情况,当您round在第一种情况下调用时,在传递给函数之前ratio * x会隐式转换为double(只能存储 15 位有效数字)。
这会导致精度损失并导致您的案例出现意外结果。没有怪癖。