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
.
A very common usage of loops is the repetitive reading of data . For example if we are entering scores of exams, it is safe to choose -1 as this unnatural score, the sentinel value, which will terminate the loop.
In programming, sentinel value is a special value that is used to terminate a loop. The sentinel value typically is chosen so as to not be a legitimate data value that the loop will encounter and attempt to perform with.
In computer programming, a sentinel value is a special value in the context of an algorithm which uses its presence as a condition of termination, typically in a loop or recursive algorithm.
Why should you be careful when choosing a sentinel value? When is it ideal to use the while loop? it is ideal in situations where you do not want the loop to iterate if the condition is false from the beginning. it is also idea if you want to use a sentinel value to terminate the loop.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With