【问题标题】:why -ffast-math option break my bool condition为什么 -ffast-math 选项会破坏我的布尔条件
【发布时间】:2016-03-07 12:56:13
【问题描述】:

这是导致问题的程序的关键部分,程序是完全顺序的。

exist_ 是类 bool 私有成员,dbl_num_ 是类 double 私有成员

exist_ = false;
dbl_num_ = 0;
std::cout << dbl_num_ << " " ;
if(exist_ == true)
{
  dbl_num_ = 5;
}else
{
  dbl_num_ = NAN;
}

std::cout << exist_ << " " << dbl_num_ << std::endl;

使用选项 -ffast-math,我得到了打印输出“0 0 5”

没有选项 -ffast-math,我得到了打印输出“0 0 NAN”

如果我将程序更改为

exist_ = false;
dbl_num_ = 0;
std::cout << dbl_num_ << " " ;
if(exist_ == true)
{
  std::cout << exist_ << " " ;
  dbl_num_ = 5;
}else
{
  dbl_num_ = NAN;
}

std::cout << exist_ << " " << dbl_num_ << std::endl;

使用选项 -ffast-math,我得到“0 0 NAN”

比我把 NAN 改成 -5

exist_ = false;
dbl_num_ = 0;
std::cout << dbl_num_ << " " ;
if(exist_ == true)
{
  dbl_num_ = 5;
}else
{
  dbl_num_ = -5;
}

std::cout << exist_ << " " << dbl_num_ << std::endl;

使用选项 -ffast-math,我得到“0 0 -5”

我知道 -ffast-math 会破坏 IEEE 标准,并且它不检查 NAN,但它破坏上述简单条件检查的具体原因是什么?

【问题讨论】:

  • exist_ 是什么? exist 是什么?请发布MCVE。无法复制。
  • 如果你想要 NaN,不要使用 -ffast-math。除其他外,编译器特别假设 NaN 不会在该标志打开时发生。
  • @user2357112 那么幕后究竟发生了什么?
  • @BryanFok - 为什么不使用 -S 选项编译并查看生成的程序集? 也许更好(更简单) - 将代码扔到gcc.godbolt.org 看看它要说什么(它显示生成的 asm 与输入的 c/c++ 代码并排显示)
  • @enhzflep 谢谢,这是一个非常酷的工具!但我无法使用简化的代码复制它。但我肯定会更多地使用它。

标签: c++ boolean fast-math


【解决方案1】:

-ffast-math 指示 g++ 假设 NaN 永远不会出现。那么,将某些东西设置为 NaN 大致相当于未定义的行为,因为编译器可以安全地假设它永远不会发生。请参阅this 系列 LLVM 博客文章,了解编译器如何消除它“知道”无法执行的分支,以及如何令人惊讶。

简短版本:g++ 进入“我们处于快速数学模式,因此 dbl_num_ 永远不会设置为 NaN,因此永远不会采用 else 分支,因此存在_必须为真,因此我可以优化除该路径之外的所有内容”。

编辑:另见this gcc 错误报告。

【讨论】:

  • 我提出了与您相同的假设,并且由于 cout 不是快速数学的最佳目标,因此分支将保留在汇编中。但不幸的是,我无法在gcc.godbolt.org 中证明这一点。
  • 我可以。 GCC 版本 4.47,标志 -ffast-math -O3 和一个接受 bool 的函数,如果 bool 为真,则返回 NAN,如果 bool 为假,则返回 5。编译为将值 5 加载到寄存器中然后返回的代码。没有优化或没有-ffast-math,测试就在那里。
猜你喜欢
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
  • 2021-11-26
  • 2011-03-25
  • 2011-08-19
  • 2013-08-14
  • 2019-09-22
  • 1970-01-01
相关资源
最近更新 更多