使用来自不同库的相同功能的不同结果

Tuğ*_*man 8 c++ cmath

这是一些代码:

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    long long int a, b;
    long long int c;

    cin >> a >> b;

    c = abs(a) + abs(b);
    cout << c;
    cout << endl;
}
Run Code Online (Sandbox Code Playgroud)

这应该返回1000000000000000002,当我输入10000000000000000002.

如果我尝试用cmath它会返回1000000000000000000,但如果我使用cstdlib它将返回1000000000000000002.为什么会发生这种情况?

还考虑到我正在使用cmath,它不应该更合适吗?

我正在使用Linux Mint 18.2 64bit,Eclipse Platform.

spe*_*ras 8

cmath版本是浮动版本.因此,当你只有那个时,你实际上对浮点数进行计算并long long最终转换回a .浮动精度不足以容纳18位数字,+ 2只会丢失.

cstdlib版本是整数版本.这给出了预期的结果.

正如评论中指出的那样,在C++ 11中,cmath还定义了一个abs采用整数的版本.但是,"这些重载在计算之前有效地将x转换为double(定义为T为任何整数类型)".

我相信如果你使用-Wall -Wextra或类似的标志,你的编译器应该给你一个转换警告,同时只包含cmath.

  • 你是对的,但不要猜测:查一查.此外,问题中的代码使用"long long",因此最后的对话是"long long",而不是"long". (2认同)

ser*_*gej 5

如果您使用的是g ++,请尝试使用-Wconversion(或-Wfloat-conversion)编译这两个版本.

请注意,该<cmath>版本会生成警告:

main.cpp:14:7:警告:从'__gnu_cxx :: __ enable_if :: __ type {aka double}'转换为'long long int' 可能会改变其值 [-Wfloat-conversion] c = abs(a)+ abs(二);

虽然<cstdlib>版本编译没有警告.

那是因为,in <cmath>,abs()定义为1:

float abs(float);
double abs(double);
long double abs(long double);
Run Code Online (Sandbox Code Playgroud)

虽然<cstdlib>它被定义为1:

int abs(int);
long abs(long);
long long abs(long long);
Run Code Online (Sandbox Code Playgroud)

1从C++ 17开始abs()定义整数版本<cmath>.