3 ms·
But in practice it's quite often the case that you know optimisations are worth it based on past experience. For example, with floating point calculations, div
by berkut 11y ago
But in practice it's quite often the case that you know optimisations are worth it based on past experience.
For example, with floating point calculations, divides are slower (on x86 anyway) than multiplies, so quite a common one in graphics/physics is to calculate the reciprocal (1.0f / x) and multiply by that if you'd do more than one divide in the first place.
The compiler can do this in some cases, but generally only with fpmath=fast, and even then, not always.
- conistonwater 11y agoFiguring out which compiler optimizations did fire, and which still need to be done by hand, is also extremely difficult. Compilers generally don't tell you. So while in principle one should be able to expect a compiler to do the $1/x$ optimization all by itself, it might be important enough to just do it by hand and get on with things.
- munchbunny 11y agoTrue, in practice there are some things that you can anticipate optimizing. However, there is such a thing as doing too much, before you know that there's a performance problem. Another good graphics/physics example is that you don't have to take the square root in a distance computation if you only care about the monotonically increasing ordering and not the exact distance. If you know that you will be dividing by magnitude or distance frequently, another optimization is to store the inverse of the magnitude instead of the original magnitude. That issue sometimes shows up in inner loops. But optimizations like that also don't have to be done up front because refactoring that kind of thing is relatively straightforward compared to switching out the underlying data structure or algorithm. My rule of thumb is that if I know I'm writing an inner loop, then I will bake in whatever best practices I already know about. Otherwise I'm going to write the feature first with generally sane architectural choices, and profile it later.
- tbirdz 11y agoOptimizing floating point calculations in this way will impact the precision of your results. Multiplying by the reciprocal will not produce the same results as a division, especially when the error is compounded over multiple operations. Using the fpmath=fast option will also let the compiler produce faster code at the cost of accuracy. Will this reduction in accuracy affect your application? For graphics and physics, maybe not, or at least not until some compounded error in an edge case makes a collision detection fail, or causes an unsightly visual error. Don't just sprinkle these optimizations throughout your code without understanding the accuracy requirements of your program.
- conistonwater 11y ago> Don't just sprinkle these optimizations throughout your code without understanding the accuracy requirements of your program. There is a relatively straightforward way to think about this. Either your program depends on fully accurate error analysis (e.g. for reproducibility), or not. If yes, you would not even think of enabling fast-math, because that's implementation-defined behaviour. If no, any mathematically valid substitution will do, unless it causes some kind of unlikely numerical instability. In the case of evaluating a/x as t=1/x;a * t, it is possible to analyze the optimization exactly: without overflows, the relative error of a * (1/x) will be at most 2u/(1-u), while relative error of a/x will be at most u. Thus this substitution is absolutely fine, there's no need to be scared of it. Mathematically sensible transformations generally produce sensible results. It is exceedingly uncommon for someone to need a perfectly rounded result.