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;
}