如果更喜欢使用-ffast-math,则哨兵值较高,可以加倍 [英] Good sentinel value for double if prefer to use -ffast-math
问题描述
由于 gcc
选项 -ffast-math
有效地禁用了 NaN
和-/+ inf
,因此我我正在寻找对性能至关重要的数学代码中表示 NaN
的下一个最佳选择.理想情况下,如果对哨兵值进行操作(添加,mul,div,sub等),将产生哨兵值,就像 NaN
一样,但是我怀疑这样做是否可行,因为我认为 NaN
是完成此操作的唯一值. -0.0
可能不是一个很好的选择,因为它也已在 -ffast-math
中禁用,并且可能会阻止某些优化,例如(x + 0.0)
,等等.
Since the gcc
option -ffast-math
effectively disables NaN
and -/+inf
, I'm looking for maybe the next best option for representing NaN
in my performance-critical math code. Ideally the sentinel value if operated on (add, mul, div, sub, etc..) would yield the sentinel value as NaN
would do but I doubt this would be possible since I think NaN
is the only value that accomplishes this. -0.0
might not be a good fit as it's also disabled in -ffast-math
and could prevent certain optimizations like (x+0.0)
, etc..
也许我的问题应该是,有什么方法可以使用 NaN
或其他特殊双精度",同时又能够启用许多数学优化而不会发生故障?
Perhaps my question should rather be, is there any way to use NaN
or some other "special double" while being able to enable a lot of the math optimizations without breaking down?
系统是 Linux/x64,gcc 4.8.1
.
推荐答案
如果您正在寻找可以通过算术运算传播的值,则 NaN
仍可与选项 -ffast一起使用.-数学
.问题出在其他地方.使用 -ffast-math
可以通过优化将某些操作从计算中删除,然后就无法保证
If you are looking for a value which would be propagated by arithmetic operations, NaN
is still available with option -ffast-math
. The problem lies somewhere else. With -ffast-math
some operations can removed from the computation due to optimization, and then there is no way to guarantee NaN
or any other value would be propagates.
例如,以下设置了 -ffast-math
的代码将导致将 0.0
硬写到 n
中,并且没有特殊值为 n
提供保护.
For example, the following, with -ffast-math
set, will cause hard writing 0.0
into n
and there is no special value for n
which would protect from it.
float n = NAN;
n *= 0.0;
您可以做的一件事是,如Shafik Yaghmour所说,将 -fno-finite-math-only -ftrapping-math
与 -ffast-math
一起使用.另外,如果只有少数几个地方您期望有一个不好的值,那么您可以自己对这些点进行准确的测试来进行检查.
One thing you can do, is to use -fno-finite-math-only -ftrapping-math
with -ffast-math
as Shafik Yaghmour said. And the other is, if there are only few places where you expect a bad value, you can check for it by yourself putting tests exactly in those points.
我认为的最后一个选择-如果您确实非常需要优化-是将 NaN
(可能还有 inf
)值手动注入到计算中,并检查是否它传播了多长时间.然后,在传播停止的那些地方,测试 NaN
( inf
)的发生.-这是一种不安全的方法,因为我不确定百分之一百可以 -ffast-math
涉及条件操作流.如果可以的话,则有很大的机会,此解决方案将无效.因此这是有风险的,如果选择,则需要涵盖计算所有分支的非常繁重的测试.
The last option I can think -- if you really badly need optimization -- is to manually inject NaN
(and maybe inf
) values into the computation and check for how long it is propagated. Then in those places where the propagation stops, test for NaN
(inf
) occurrence. -- This is an unsafe method, as I am not one hundred percent sure, can -ffast-math
involve conditional flow of operations. If it can, there is a significant chance, this solution will be invalid. So it is risky and if chosen needs very heavy testing covering all branches of the computation.
通常我宁愿反对最后一个解决方案,但实际上有机会将 NaN
( inf
)值传播到整个计算或几乎整个计算中,因此它可以提供您想要的性能.因此,您可能要冒险.
Normally I would be rather against the last solution, but actually there is a chance, NaN
(inf
) values will be propagated though the whole computation or almost whole, so it can give the performance you are seeking for. So you may want to take the risk.
可以使用 -ffast-math
检查 NaN
,就像Shafik Yaghmour所说的那样,
Checking for NaN
with -ffast-math
you can do, as Shafik Yaghmour said, with
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
.
这篇关于如果更喜欢使用-ffast-math,则哨兵值较高,可以加倍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!