Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good sentinel value for double if prefer to use -ffast-math

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.

like image 460
stgtscc Avatar asked Jul 12 '13 12:07

stgtscc


People also ask

Which is an example of a sentinel value in use?

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.

Why is sentinel value required?

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.

What is sentinel value?

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.

What is sentinel value and why should you be careful when choosing a sentinel value?

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.


1 Answers

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.

like image 66
Clare Avatar answered Sep 28 '22 21:09

Clare