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

时间:2013-07-12 12:28:12

标签: c optimization double 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

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)值注入计算并检查它传播的时间。然后在传播停止的那些地方,测试NaNinf)次发生。 - 这是一种不安全的方法,因为我不是百分之百肯定,可以-ffast-math涉及有条件的操作流程。如果可以的话,这个解决方案很有可能无效。所以它有风险,如果选择需要非常繁重的测试,涵盖计算的所有分支。

通常我会反对上一个解决方案,但实际上有一个机会,NaNinf)值将通过整个计算或几乎整个传播,因此它可以提供性能你在寻找。所以你可能想承担风险。


正如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}}。