如果您正在寻找将通过算术运算传播的值,NaN
仍然可以使用 option -ffast-math
。问题出在其他地方。由于-ffast-math
优化可以从计算中删除一些操作,然后没有办法保证NaN
或任何其他值将被传播。
例如,带有-ffast-math
set 的以下内容将导致硬写入0.0
,n
并且没有n
可以保护它的特殊值。
float n = NAN;
n *= 0.0;
您可以做的一件事就是使用-fno-finite-math-only -ftrapping-math
with ,-ffast-math
就像 Shafik Yaghmour 所说的那样。另一个是,如果只有少数地方你期望一个坏的值,你可以自己检查它,在这些点上进行测试。
我能想到的最后一个选择——如果你真的非常需要优化——是手动注入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
。