如果更喜欢使用 -ffast-math,则为双倍的良好哨兵价值

Posted

技术标签:

【中文标题】如果更喜欢使用 -ffast-math,则为双倍的良好哨兵价值【英文标题】:Good sentinel value for double if prefer to use -ffast-math 【发布时间】:2013-07-10 23:56:57 【问题描述】:

由于gcc 选项-ffast-math 有效地禁用了NaN-/+inf,我正在寻找在我的性能关键数学代码中表示NaN 的下一个最佳选项。理想情况下,如果对(add、mul、div、sub 等)进行操作,sentinel 值会像NaN 那样产生sentinel 值,但我怀疑这是可能的,因为我认为NaN 是唯一可以完成的值这。 -0.0 可能不太适合,因为它在 -ffast-math 中也被禁用,并且可能会阻止某些优化,例如 (x+0.0) 等。

也许我的问题应该是,有没有什么方法可以使用NaN 或其他一些“特殊双精度”,同时能够在不崩溃的情况下启用大量数学优化?

系统是Linux/x64, gcc 4.8.1

【问题讨论】:

这个帖子可能会有所帮助Mingw32 std::isnan with -ffast-math @ShafikYaghmour 谢谢,这个帖子很有帮助。 还有使用-fno-finite-math-only -ftrapping-mathlua-users.org/lists/lua-l/2009-04/msg00091.html的选项 我同样想知道返回浮点值的函数的良好哨兵。我决定使用optional,如optional<float>optional<double>。除了明确意图之外,我认为这还具有对快速数学等编译器选项不太敏感的优点。这当然需要 C++17,或者使用 boost::optional 或编写自己的 optional 实现(这是我所做的,这对我来说似乎很容易)。 【参考方案1】:

如果您正在寻找一个可以通过算术运算传播的值,NaN 仍然可以通过选项-ffast-math 获得。问题出在其他地方。使用-ffast-math,由于优化,某些操作可以从计算中删除,然后无法保证NaN 或任何其他值会传播。

例如,以下设置了-ffast-math,将导致将0.0 硬写入n,并且n 没有特殊值可以保护它。

float n = NAN;
n *= 0.0;

您可以做的一件事是使用 -fno-finite-math-only -ftrapping-math-ffast-math,正如 Shafik Yaghmour 所说。另一个是,如果只有少数几个地方你期望一个错误的值,你可以自己在这些点上进行测试来检查它。

我能想到的最后一个选项——如果你真的非常需要优化——是手动将NaN(可能还有inf)值注入到计算中,并检查它传播了多长时间。然后在传播停止的地方,测试NaN (inf) 的出现。 -- 这是一种不安全的方法,我不能百分百肯定,-ffast-math 是否可以涉及有条件的操作流。如果可以,则很有可能该解决方案将无效。所以这是有风险的,如果选择需要覆盖计算的所有分支的非常繁重的测试。

通常我宁愿反对最后一个解决方案,但实际上有一个机会,NaN (inf) 值将通过整个计算或几乎整个传播,因此它可以提供您正在寻求的性能.所以你可能想冒险。


使用-ffast-math 检查NaN,正如Shafik Yaghmour 所说,使用

inline int isnan(float f)

    union  float f; uint32_t x;  u =  f ;
    return (u.x << 1) > 0xff000000u;

对于double

inline int isnan(double d)

    union  double d; uint64_t x;  u =  d ;
    return (u.x << 1) > 0xff70000000000000ull;

检查inf 将是

inline int isinf(float f)

    union  float f; uint32_t x;  u =  f ;
    return (u.x << 1) == 0xff000000u;


inline int isinf(double d)

    union  double d; uint64_t x;  u =  d ;
    return (u.x << 1) == 0xff70000000000000ull;

你也可以合并isnanisinf

【讨论】:

上面的isnan和isinf应该是0xffe0000000000000ull而不是0xff70000000000000ull。

以上是关于如果更喜欢使用 -ffast-math,则为双倍的良好哨兵价值的主要内容,如果未能解决你的问题,请参考以下文章

有啥理由更喜欢 System.arraycopy() 而不是 clone()?

Entitymanager.flush() VS EntityManager.getTransaction().commit - 我应该更喜欢啥?

text Eslint规则更喜欢asyc等待

sh ssh更喜欢密码

r 你更喜欢哪种方法?

为啥 Visual Studio 2005 更喜欢“无”而不是 perforce 作为源代码控制提供程序