问题
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..
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?
System is Linux/x64, gcc 4.8.1
.
回答1:
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.
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;
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.
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.
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.
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;
}
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
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
.
来源:https://stackoverflow.com/questions/17614943/good-sentinel-value-for-double-if-prefer-to-use-ffast-math