Is this sort of 'optimization' necessary?

Started by
15 comments, last by iMalc 18 years, 7 months ago
I see in many pieces of code things like.
partial_calculation=sqrt(pow(abs(x-y))*pow(abs(x-y)));
complete_calculation1+=(partial_calculation*whatever)+something_else;
complete_calculation2+=(partial_calculation*whatever)+something_else;
complete_calculation3+=(partial_calculation*whatever)+something_else;
complete_calculation4+=(partial_calculation*whatever)+something_else;
I mean, code that makes some partial calculations and stores them in a variable and then reuses that variable to calculate some other results, when that partial calculation could have just been inlined in the next lines like so:
complete_calculation1+=(sqrt(pow(abs(x-y))*pow(abs(x-y))))*whatever)+something_else;
complete_calculation2+=(sqrt(pow(abs(x-y))*pow(abs(x-y))))*whatever)+something_else;
complete_calculation3+=(sqrt(pow(abs(x-y))*pow(abs(x-y))))*whatever)+something_else;
complete_calculation4+=(sqrt(pow(abs(x-y))*pow(abs(x-y))))*whatever)+something_else;
So i've been wondering, is this done just for clarity, or is there some benifit to the performance, because when i think of it, it kind of seems like "sqrt(pow(abs(x-y))*pow(abs(x-y)))" is going to be cached and there is no need to store it in another variable in the first place.
Advertisement
You can assume the compiler's smart enough to do that for you, or you can take the safe path and store the extra varaible yourself. If the compiler doesn't do it, the second method is bound to be slower.
Any compiler that can't do that for you is crap, so it shouldn't be neccessary. But for clarity, I would do it anyway.
Unless intrinsics are enabled, the compiler may not be able to assume that a call to pow or abs with a constant value will have a constant result. So in the latter case, the sqrt, pow, etc. could end up getting calculated every time. I'd strongly recommend the former, as it makes sure you don't blow off cycles unnecessarily.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Yeah, since it's so easy to do (and gives you cleaner code), you might as well. In the best case, you've made an optimization, at the worst case, you've got cleaner code that performs exactly the same.

No real downside, is there? [wink]

It also makes it a lot easier for you if you have to change that formula later on. (Nothing worse than having to search and replace 30 instances of it... Except when you replace 29 and forget one, and get weird bugs because of it)

So much easier (and safer, and potentially faster) to just store the first calculation in a variable you can use afterwards.
Common subexpression elimination.

Quote:Unless intrinsics are enabled, the compiler may not be able to assume that a call to pow or abs with a constant value will have a constant result. So in the latter case, the sqrt, pow, etc. could end up getting calculated every time.


GCC lets you tag a function with the pure attribute, telling the compiler that the function has no side-effects and that the return value depends only on globals and function parameters. You can go one step further and add the const attribute (which isn't the same thing as using the const keyword in a normal C or C++ sense), which tell the compiler that the function doesn't rely on global memory at all (that includes not dereferencing pointers passed as parameters either). Both allow the compiler to perform common subexpression elimination on the function call.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Do it for clarity, because if you are in the habit of trying to 'inline' everything, you are bound to screw up sooner or later (e.g. by not accounting for re-negating a negative properly, or by trying to "simplify" a huge expression manually and messing it up). Also because short code* just looks better :)

* short in the sense of number of things that "appear to be done"; don't go using all one-letter variable names on me now.
Is there something like the pure attribute for C#? I know it isn't a keyword but I suppose it might be some obscure attribute.

EDIT: but I suppose unless you're using unsafe code, the compiler could do that automatically. Probably does. How lovely [smile]
Whether it's more optimized or not you should store the result and reuse it anyway. Don't embrace code redundancy! Let's weigh the benefits of each:

The one with the partial calculation makes the complex calculation only appear once in code to the person looking at it. One simple identifier is used in the following expressions making it easy to see that it's the same value used. Both a programmer and a compiler can much more easily see that you only need to do those calculations and call that function only once, using the return for all of the remaining calculations. You can give that intermediate calculation a name that identifies what it represents in the following expressions, making it more clear as to what you are doing. You have one more line of written code, but you have much less operations. If you wish to change how the calculation is performed, you only have to change it once for the entire group of statements as opposed to once for each line. Finally, it's possible that the code will be more optimized, since in order to make that optimization the compiler would have to know that the functions you are calling produce the same result every time for the same values.

Now, what exactly do you think you benefit from showing the redundant calculation in code? Sure, you have one less line of code, but you have a lot more operations; most of which are redundant. It is less obvious to a reader or a compiler that the calculation has the same result in each expression. The expression is harder to read. It's possibly less optimized, and finally, it's harder to maintain.

Go with storing the partial calculation.
Quote:Original post by Fruny
GCC lets you tag a function with the pure attribute, telling the compiler that the function has no side-effects and that the return value depends only on globals and function parameters. You can go one step further and add the const attribute (which isn't the same thing as using the const keyword in a normal C or C++ sense), which tell the compiler that the function doesn't rely on global memory at all (that includes not dereferencing pointers passed as parameters either). Both allow the compiler to perform common subexpression elimination on the function call.

I was thinking something exactly like the const attribute would be really useful in VC++ only the other day. Interesting to know that it exists for GCC. You don't know if there's anything equivalent for VC++ (2005) do you?

Game Programming Blog: www.mattnewport.com/blog

This topic is closed to new replies.

Advertisement