IEEE floating point optimization - guaranteed math identities?

I am having some problems with IEEE floating point rules that prevent compiler optimizations that seem obvious. For instance,

char foo(float x) { if (x == x) return 1; else return 0; } 

cannot be optimized to just return 1, because NaN == NaN is false. Okay, fine, I think.

However, I want to write so that the optimizer can actually fix something for me. Are there mathematical identities for all floats? For example, I would like to write! (X - x), if that meant that the compiler could assume that it held on all the time (although this is also not the case).

I see some links to such identifiers on the Internet, for example here , but I did not find organized information, including an easy scan of the IEEE 754 standard.

It would be great if I could force the optimizer to accept isnormal (x) without generating additional code (in gcc or clang).

Obviously, I am not going to write (x == x) in my source code, but I have a function designed for inline. A function can be declared as foo (float x, float y), but often x is 0 or y is 0, or x and y are both z, etc. Floats are screen geometric coordinates. These are all cases when I manually encoded without using a function that I would never distinguish between 0 and (x - x), I would just optimize the dumb things. So, I really don't care about the IEEE rules in what the compiler does after turning on my function, and I would immediately ignore their compiler. Rounding differences are also not very important, since we mainly do a screen drawing.

I don’t think that -ffast-math is an option for me, because the function appears in the header file, and it doesn’t work that the .c files that use this function compile with -ffast-math.

+4
source share
5 answers

Another tip you might find useful is a really good article on floating point optimization in Game Programming Gems Volume 2, Yossarian King. You can read the article here . It details the IEEE format, taking into account implementations and architecture, and provides many optimization tricks.

+2
source

I think that you will always struggle for the computer floating point arithmetic to behave like a real number mathematical arithmetic, and assume that you are not for any reason. I suggest you make a mistake like trying to compare the equality of numbers 2 fp. Since the numbers fp are overwhelmingly close, you should take this and use approximate equality as a test.

Integer numbers of computers exist to verify the equality of numerical values.

It's good that I think you go ahead and fight the car (well, all the cars are actually) if you want.

Now, to answer some parts of your question:

- for each mathematical identity with which you are familiar from the arithmetic of a real number, in the field of floating point numbers there are examples of counterparts, whether IEEE or otherwise;

- “smart” programming almost always complicates code optimization for the compiler than simple programming;

- it seems that you are doing graphical programming: as a result, the coordinates of the points in your conceptual space will be displayed in pixels on the screen; pixels always have integer coordinates; your transfer from conceptual space to screen space defines your approximate equality function

Hi

Mark

+2
source

If you can assume that the floating point numbers used in this module will not be Inf / NaN, you can compile it with -ffinite-math-only (in GCC). This can “improve” the code for examples like the one you posted.

+1
source

You can compare bitwise equality. Although you can bite some values ​​that are equivalent but bitwise, they will catch all those cases where you have true equality, as you mentioned. And I'm not sure that the compiler will know what you are doing, and delete it when pasting (which, I believe, is what you need), but it's easy to check.

+1
source

What happened when you tried it in the obvious way and profiled it? or reviewed the generated asm?

If the function is embedded with values ​​known on the call site, the optimizer has this information. For example: foo(0, y) .

You may be surprised at what you do not need to do, but at least profiling or looking at what the compiler really does with the code will provide you with additional information and help you figure out where to go next.

However, if you know certain things that the optimizer cannot understand, you can write several versions of the function and specify the one you want to call. This is a bit of a hassle, but at least with the built-in functions they will be listed together in one header. It is also a little easier than the next step, which uses the built-in asm to do exactly what you want.

0
source

All Articles