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..
由于gcc选项-ffast-math有效地禁用了NaN和 - / + inf,我正在寻找可能是在我的性能关键数学代码中表示NaN的下一个最佳选项。理想情况下,如果对(add,mul,div,sub等)进行操作,哨兵值会产生哨兵值,因为NaN会做,但我怀疑这是可能的,因为我认为NaN是实现这一点的唯一值。 -0.0可能不太合适,因为它在-ffast-math中也被禁用,并且可能会阻止某些优化,如(x + 0.0)等。
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?
也许我的问题应该是,有没有办法使用NaN或其他一些“特殊的双重”,同时能够启用大量的数学优化而不会破坏?
System is Linux/x64, gcc 4.8.1
.
系统是Linux / x64,gcc 4.8.1。
1 个解决方案
#1
4
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.
如果要查找将通过算术运算传播的值,则NaN仍可使用-ffast-math选项。问题出在其他地方。使用-ffast-math,由于优化,某些操作可以从计算中删除,然后无法保证NaN或任何其他值将被传播。
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.
例如,下面的-ffast-math设置将导致硬写入0.0到n并且n没有特殊值可以保护它。
float n = NAN;
n *= 0.0;
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.
你可以做的一件事就是使用-fno-finite-math-only -ftrapping-math with -ffast-math,正如Shafik Yaghmour所说。另一方面,如果只有少数几个地方你期望一个不好的价值,你可以自己检查它,将测试完全放在这些点上。
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)值注入计算并检查它传播的时间。然后在传播停止的那些地方,测试NaN(inf)的发生。 - 这是一种不安全的方法,因为我不是百分之百确定,-ffast-math涉及有条件的操作流程。如果可以的话,这个解决方案很有可能无效。所以它有风险,如果选择需要非常繁重的测试,涵盖计算的所有分支。
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.
通常我会反对最后的解决方案,但实际上有可能,NaN(inf)值将通过整个计算或几乎整体传播,因此它可以提供您正在寻求的性能。所以你可能想承担风险。
Checking for NaN
with -ffast-math
you can do, as Shafik Yaghmour said, with
正如Shafik Yaghmour所说,你可以用-ffast-math检查NaN
inline int isnan(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}
and for double
with
和双倍的
inline int isnan(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) > 0xff70000000000000ull;
}
Checking for inf
would be
检查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;
}
You can also merge isnan
and isinf
.
你也可以合并isnan和isinf。
#1
4
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.
如果要查找将通过算术运算传播的值,则NaN仍可使用-ffast-math选项。问题出在其他地方。使用-ffast-math,由于优化,某些操作可以从计算中删除,然后无法保证NaN或任何其他值将被传播。
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.
例如,下面的-ffast-math设置将导致硬写入0.0到n并且n没有特殊值可以保护它。
float n = NAN;
n *= 0.0;
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.
你可以做的一件事就是使用-fno-finite-math-only -ftrapping-math with -ffast-math,正如Shafik Yaghmour所说。另一方面,如果只有少数几个地方你期望一个不好的价值,你可以自己检查它,将测试完全放在这些点上。
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)值注入计算并检查它传播的时间。然后在传播停止的那些地方,测试NaN(inf)的发生。 - 这是一种不安全的方法,因为我不是百分之百确定,-ffast-math涉及有条件的操作流程。如果可以的话,这个解决方案很有可能无效。所以它有风险,如果选择需要非常繁重的测试,涵盖计算的所有分支。
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.
通常我会反对最后的解决方案,但实际上有可能,NaN(inf)值将通过整个计算或几乎整体传播,因此它可以提供您正在寻求的性能。所以你可能想承担风险。
Checking for NaN
with -ffast-math
you can do, as Shafik Yaghmour said, with
正如Shafik Yaghmour所说,你可以用-ffast-math检查NaN
inline int isnan(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}
and for double
with
和双倍的
inline int isnan(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) > 0xff70000000000000ull;
}
Checking for inf
would be
检查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;
}
You can also merge isnan
and isinf
.
你也可以合并isnan和isinf。