由于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
。
答案 0 :(得分:4)
如果您正在寻找可通过算术运算传播的值,NaN
仍可使用选项-ffast-math
。问题出在其他地方。使用-ffast-math
,由于优化,某些操作可以从计算中删除,然后无法保证NaN
或任何其他值将被传播。
例如,如果设置了-ffast-math
,则以下内容会导致0.0
写入n
,并且n
没有特殊值可以保护它。
float n = NAN;
n *= 0.0;
Shafik Yaghmour说,你可以做的一件事就是-fno-finite-math-only -ftrapping-math
与-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;
}
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;
}
将是
isnan
您还可以合并isinf
和{{1}}。