Reputation: 6029
I currently have code that looks like
while (very_long_loop) {
...
y1 = getSomeValue();
...
x1 = y1*cos(PI/2);
x2 = y2*cos(SOME_CONSTANT);
...
outputValues(x1, x2, ...);
}
the obvious optimization would be to compute the cosines ahead-of-time. I could do this by filling an array with the values but I was wondering would it be possible to make the compiler compute these at compile-time?
Edit: I know that C doesn't have compile-time evaluation but I was hoping there would had been some weird and ugly way to do this with macros.
Upvotes: 6
Views: 2111
Reputation: 169563
If you're lucky, you won't have to do anything: Modern compilers do constant propagation for functions in the same translation unit and intrinsic functions (which most likely will include the math functions).
Look at the assembly to check if that's the case for your compiler and increase the optimization levels if necessary.
Upvotes: 7
Reputation: 39045
You assume that computing cos
is more expensive than an access. Perhaps this is not true on your architecture. Thus you should do some testing (profiling) - as always with optimization ideas.
Upvotes: 1
Reputation: 4462
I am struck with awe by Christoph's answer above.
So nothing needs to be done in this case, where gcc has some knowledge about the math functions. But if you have a function (maybe implemented by you) which cannot be calculated by your C compiler or if your C compiler is not so clever (or you need to fill complicated data structures or some other reason) you can use some higher level language to act as macroprocessor. In the past, I have used eRuby for this purpose, but (ePerl should work very well too and is another obvious readily available and more or less comfortable choice.
You can specify make rules for transforming files with extension .eruby
(or .eperl
or whatever) to files with that extension stripped out so that, for example, if you write files module.c.eruby
or module.h.eruby
then make
automatically knows how to generate module.c
or module.h
, respectively, and keeps them up-to-date. In your make rule you can easily add generation of comment that warns editing the file directly.
If you are using Windows or something similar, then I am out of my depths in explaining how to add support for running this transformation automatically for you by your favorite IDE. But I believe it should be possible, or you could just run make
outside of your IDE whenever you need to change those .eruby
(or whatever) files.
By the way, I have seen that with incredibly small lines of code I have seen eLua implemented to use Lua as a macro language. Of course any other scripting language with support for regular expressions and flexible layout rules should work as well (but Python is malsuited for this purpose due to strict white space rules).
Upvotes: 0
Reputation: 49311
If you check the code and the compiler is not hoisting the constant values out of the loop, then do so yourself.
If the arguments to the trig functions are constant as in your sample code, then either pre-compute them yourself, or make them static variables so they are only computed once. If they vary between calls, but are constant within the loop then move them to outside the loop. If they vary between iterations of the loop, then a look-up table may be faster, but if that is acceptable accuracy then implementing your own trig functions which halt the calculation at a lower accuracy is also an option.
Upvotes: 0
Reputation: 272487
No, unfortunately.
I would recommend writing a little program (or script) that generates a list of these values (which you can then #include
into the correct place), that is run as part of your build process.
By the way: cos(pi/2) = 0!
Upvotes: 1
Reputation: 78903
No, C doesn't have the concept of compile time evaluation of functions and not even of symbolic constants if they are of type double. The only way to have them as immediate operand would be to precompute them and then to define them in macros. This is the way the C library does it for pi for example.
Upvotes: 0
Reputation: 798606
Instead of precomputing these values, it is possible to use global variables to hold the values, which would be computed once on program startup.
Upvotes: 0
Reputation: 300539
Nope. A pre-computed lookup table would be the only way. In fact, Cosine
(and Sine
) might even be implemented that way in your libraries.
Profile first, Optimise Later.
Upvotes: 1