对于一些非常大的双精度值,abs()返回一个负值

abs() returns a negative value for some very large double values

本文关键字:返回 一个 非常 于一些 双精度 abs      更新时间:2023-10-16

我使用了一些大的双值,所有的数学函数都很好。sqrt、pow和其他数学函数似乎对大的科学双值没有任何问题,但abs无法处理这些数字。例如,这是可以的:

double s = sqrt(3.9 * 1e32);

但这不是:

double s = sqrt(abs(3.9 * 1e32));

因为abs返回负值;我不明白为什么这个简单的函数不能处理科学的双重运算,而所有这些复杂的运算都很好。是我遗漏了什么,还是真的是这样,我不能使用c++abs函数来获得这样的值?

MCVE

#include <cstdlib>
#include <cstdio>
int main()
{
    double d = 3.9e32;
    double f = abs(d);
    std::printf("%fn", f);
}

结果

  • 大肠杆菌:2147483647.000000
  • g++4.8.3-密码:-2147483648.000000

在此MCVE中,将abs更改为std::abs会由于过载解析失败而导致编译错误(无法在std::abs<int>std::abs<long>std::abs<long long>之间进行选择)。

问题是,当您在C++中需要fabs(double)或更好的std::abs()时,您正在使用abs(int)。你说你试过std::abs(),但如果你有,它就会解决你的问题。

这是C++中一个不幸而常见的陷阱。在正面没有std::的情况下,切勿使用abs()。这很危险。

其他答案中提到的abs在C++中返回int的说法是完全不正确的。在C++标准库中,函数abs被重载用于不同的参数(和返回)类型。标头<stdlib.h>(或<cstdlib>)为整型参数提供重载。标头<math.h>(或<cmath>)为浮点参数提供重载。

这种情况下的问题是OP在程序中使用了哪个头文件。如果包含<math.h>,那么abs应该调用double abs(double)并生成正确的结果(除非编译器坏了)。如果包括<stdlib.h>(并且没有<math.h>),则由于abs(int)abs(long)都可用,该调用应该导致过载解决失败。

这同样适用于absstd::abs。您应该使用哪一个仅取决于您包含的头文件:<stdlib.h>-<math.h><cstdlib>-<cmath>。请注意,使用std::abs而不是abs对这个问题根本没有任何影响:在这两种情况下,重载函数集是相同的。

如果在OP的情况下调用absint版本,这将是实现的一个怪癖。实际上有一个DR处理这个问题

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2380