【问题标题】:abs() returns a negative value for some very large double valuesabs() 对一些非常大的双精度值返回负值
【发布时间】:2014-10-04 06:21:34
【问题描述】:

我正在处理一些大的 double 值,所有数学函数都很好。看起来 sqrt、pow 和其他数学函数对大的科学 double 值没有任何问题,但 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("%f\n", f);
}

结果

  • Coliru: 2147483647.000000
  • g++ 4.8.3-cygwin:-2147483648.000000

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

【问题讨论】:

  • ideone.com/6CkMVS工作正常
  • 是的,约翰,真正的代码是有效的。我只是在这里写的,没有复制代码。
  • 你说得对,R Sahu,它在那里工作得很好。但在我在 Linux 上的 Qt 项目中,它得到了 -nan
  • 好吧,我向你保证abs() 永远不会返回负数。也许您正在将其转换为 int 或其他内容。您需要准确打印出表达式的每个部分在每个步骤中包含的内容。始终,始终在 C++ 中显式使用std::abs(),因为abs() 很危险:它返回int
  • 如何验证 abs 的输出为负值?

标签: c++ absolute


【解决方案1】:

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

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

【讨论】:

  • 3.9 * 1e32 用作参数时,选择abs(int) 会不会导致类型错误?
  • 好吧,你是对的!谢谢。但 fabs 在这里工作不正常
  • 误导性答案。无需在 C++ 代码中使用 fabs。只要包含正确的头文件,函数abs 就会对所有参数类型进行重载。
  • @AndreyT:我确实说过“在 C++ 中更好,std::abs()。”如果我的英语不够清楚,那意味着“如果您使用 C++,请始终使用std::abs()。”
  • @user2864740 不,C++ 具有从 double 到 int 的隐式转换。 (如果双精度大于INT_MAX,则会导致未定义的行为。
【解决方案2】:

其他答案中提到的abs 在 C++ 中返回 int 的说法是完全错误的。在 C++ 标准库中,函数 abs 针对不同的参数(和返回)类型进行了重载。标头&lt;stdlib.h&gt;(或&lt;cstdlib&gt;)为整数参数提供重载。标头&lt;math.h&gt;(或&lt;cmath&gt;)为浮点参数提供重载。

这种情况下的问题是OP在程序中使用了哪个头文件。如果包含&lt;math.h&gt;,则abs 应该调用double abs(double) 并生成正确的结果(除非编译器损坏)。如果包含&lt;stdlib.h&gt;(并且不包含&lt;math.h&gt;),那么由于abs(int)abs(long) 的可用性,调用应该会导致重载解析失败。

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

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

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

【讨论】:

  • 我在原帖中添加了一个 MCVE,我猜我们周围有很多损坏的库,或者有人忽略了一些东西!
  • ISTR 未指定来自 std:: 的名称是否也注入全局命名空间;所以也许允许实现将int abs(int) 注入全局而不是其他任何地方? (或什么)
  • @Matt McNabb:是的,但是你为什么在包含&lt;c..&gt; 样式标题后调用abs(而不是std::abs)?形式上,代码在一般情况下无效。剩下的就是实施的怪癖。
  • 我正在做abs 当然会产生这个问题! :)
  • 很好地解释了我认为 OP 的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多