如果喜欢使用-ffast-math,那么double的好哨兵值

stg*_*scc 10 c double optimization nan fast-math

由于gcc选项-ffast-math有效地禁止NaN-/+inf,我在寻找可能的表示下一个最好的选择,NaN在我的性能关键数学代码.理想情况下,如果对(add,mul,div,sub等)进行操作,哨兵值会产生哨兵值,NaN但我怀疑这是可能的,因为我认为这NaN是实现这一目标的唯一价值. -0.0可能不太适合,因为它也被禁用,-ffast-math并可能阻止某些优化,如(x+0.0)等.

也许我的问题应该是,是否有任何方法可以使用NaN或其他"特殊双重",同时能够启用大量的数学优化而不会崩溃?

系统是Linux/x64, gcc 4.8.1.

Cla*_*are 4

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

例如,以下带有-ffast-mathset 的内容将导致硬写入0.0n并且没有特殊值n可以防止它。

float n = NAN;
n *= 0.0;
Run Code Online (Sandbox Code Playgroud)

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

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

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


正如 Shafik Yaghmour 所说,检查NaN你可以做的事情-ffast-math

inline int isnan(float f)
{
    union { float f; uint32_t x; } u = { f };
    return (u.x << 1) > 0xff000000u;
}
Run Code Online (Sandbox Code Playgroud)

和对于double

inline int isnan(double d)
{
    union { double d; uint64_t x; } u = { d };
    return (u.x << 1) > 0xff70000000000000ull;
}
Run Code Online (Sandbox Code Playgroud)

检查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;
}
Run Code Online (Sandbox Code Playgroud)

您还可以合并isnanisinf