C 如果喜欢使用-ffast数学,则双精度的良好哨兵值
由于C 如果喜欢使用-ffast数学,则双精度的良好哨兵值,c,optimization,double,nan,fast-math,C,Optimization,Double,Nan,Fast Math,由于gcc选项-ffast math有效地禁用了NaN和-/+inf,因此我正在寻找在性能关键数学代码中表示NaN的下一个最佳选项。理想情况下,如果对sentinel值(add、mul、div、sub等)进行操作,则会产生sentinel值,就像NaN那样,但我怀疑这是否可能,因为我认为NaN是唯一实现这一点的值-0.0可能不太合适,因为它在-ffast math中也被禁用,可能会阻止某些优化,如(x+0.0)等 也许我的问题应该是,是否有任何方法可以使用NaN或其他“特殊双精度”,同时能够在不
gcc
选项-ffast math
有效地禁用了NaN
和-/+inf
,因此我正在寻找在性能关键数学代码中表示NaN
的下一个最佳选项。理想情况下,如果对sentinel值(add、mul、div、sub等)进行操作,则会产生sentinel值,就像NaN
那样,但我怀疑这是否可能,因为我认为NaN
是唯一实现这一点的值-0.0
可能不太合适,因为它在-ffast math
中也被禁用,可能会阻止某些优化,如(x+0.0)
等
也许我的问题应该是,是否有任何方法可以使用NaN
或其他“特殊双精度”,同时能够在不发生故障的情况下启用大量数学优化
系统是
Linux/x64,gcc 4.8.1
如果您正在寻找一个可以通过算术运算传播的值,NaN
仍然可以使用选项-ffast math
。问题出在别的地方。使用-ffast math
时,由于优化,某些操作可以从计算中删除,因此无法保证NaN
或传播任何其他值
例如,在设置了-ffast math
的情况下,以下内容将导致将0.0
硬写入n
,并且n
没有特殊的值可以保护它。
你可以做的一件事,就是使用-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;
}
检查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;
}
inline int-isinf(浮点f)
{
并集{float f;uint32_t x;}u={f};
返回(u.x此线程可能会有帮助@ShafikYaghmour谢谢,该线程很有帮助。还可以选择使用-fno finite math only-ftrapping math
我同样一直在想,对于返回浮点值的函数,是否有好的哨兵。我决定使用optional
作为optional
或o可选的
。除了明确意图之外,我认为这还有一个优点,即对编译器选项不太敏感,比如快速数学。这当然需要C++17,或者使用boost::optional
,或者编写自己的optional
实现(这就是我做的,对我来说似乎很容易)。对于上面的isnan和isinf,它应该是0xFF0000000000000ull,而不是0xFF700000000000ull。
inline int isnan(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) > 0xff70000000000000ull;
}
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;
}