浮点除以零的行为

新手上路,请多包涵

考虑

#include <iostream>
int main()
{
    double a = 1.0 / 0;
    double b = -1.0 / 0;
    double c = 0.0 / 0;
    std::cout << a << b << c; // to stop compilers from optimising out the code.
}

我一直以为 a 会是+Inf, b 会是-Inf, c 会是NaN。但我也听说过严格来说浮点除以零的行为是 未定义 的,因此上述代码不能被认为是可移植的 C++。 (这在理论上抹杀了我的百万行加代码堆栈的完整性。哎呀。)

谁是正确的?

注意我对 实现定义 很满意,但我在这里谈论的是吃猫,打喷嚏的 _未定义行为_。

原文由 Bathsheba 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

除以零整数和浮点都是未定义的行为 [expr.mul]p4

二元 / 运算符产生商,二元 % 运算符产生第一个表达式除以第二个表达式的余数。 如果 / 或 % 的第二个操作数为零,则行为未定义。

虽然实现可以选择支持 附件 F ,它具有明确定义的浮点除零语义。

我们可以从这个 clang 错误报告中看到 clang sanitizer 认为 IEC 60559 浮点除以零是未定义 的,即使宏 STDC_IEC_559 已定义,它也是由系统头文件定义的,至少对于 clang 不支持 附件 F 等对于 clang 仍然是未定义的行为:

C 标准的附件 F(IEC 60559 / IEEE 754 支持)定义了浮点除以零,但 clang(3.3 和 3.4 Debian 快照)认为它是未定义的。这是不正确的:

对附件 F 的支持是可选的,我们不支持它。

#if STDC_IEC_559

这个宏是由您的系统头文件定义的,而不是由我们定义的;这是您的系统标头中的错误。 (FWIW,GCC 也不完全支持 Annex F,IIRC,所以它甚至不是 Clang 特定的错误。)

该错误报告和其他两个错误报告 UBSan: Floating point division by zero is not undefined and clang should support Annex F of ISO C (IEC 60559 / IEEE 754) 表明 gcc 在浮点除以零方面符合 附录 F .

尽管我同意 C 库不能无条件地定义 STDC_IEC_559 ,但问题是特定于 clang 的。 GCC 并不完全支持 Annex F,但至少它的意图是在默认情况下支持它,并且如果舍入模式未更改,则除法已明确定义。 现在不支持 IEEE 754(至少是处理除零等基本功能)被认为是不良行为。

这是 GCC wiki 中浮点数学的 gcc Semantics 的 进一步支持,这表明 -fno-signaling-nans 是默认值,与 gcc 优化选项文档 一致,该文档说:

默认值为 -fno-signaling-nans。

有趣的是,clang 的 UBSan 默认在 -fsanitize=undefined 下包含 _浮点除零_,而 gcc 没有

检测浮点除以零。与其他类似选项不同, -fsanitize=float-divide-by-zero 不是由 -fsanitize=undefined 启用的,因为浮点除以零可能是获得无穷大和 NaN 的合法方式。

看到它 为 clang活,为 gcc 而活。

原文由 Shafik Yaghmour 发布,翻译遵循 CC BY-SA 4.0 许可协议

C++ 标准不强制 IEEE 754 标准,因为这主要取决于硬件架构。

如果硬件/编译器正确实现了 IEEE 754 标准,则该部门将提供预期的 INF、-INF 和 NaN,否则……这取决于。

未定义意味着,编译器实现决定,并且有很多变量,如硬件架构、代码生成效率、编译器开发人员的惰性等。

资源:

除以 0.0 的 C++ 标准状态是 undefined

C++ 标准 5.6.4

…如果 / 或 % 的第二个操作数为零,则行为未定义

C++ 标准 18.3.2.4

…静态 constexpr bool is_iec559;

…56。当且仅当类型符合 IEC 559 标准时为真。217

…57。对所有浮点类型都有意义。

IEEE754的C++检测:

标准库包含一个模板来检测是否支持 IEEE754:

静态 constexpr bool is_iec559;

 #include <numeric>
bool isFloatIeee754 = std::numeric_limits<float>::is_iec559();

如果不支持 IEEE754 怎么办?

这取决于,通常除以 0 会触发硬件异常并使应用程序终止。

原文由 Adrian Maire 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏