C non-trivial constants
I want to make several constants in C with #define to speed up computation. Two of them are not simply trivial numbers, where one is a right shift, the other is a power. math.h
in C gives the function pow() for doubles, whereas I need powers for integers, so I wrote my own function, ipow
, so I wouldn't need to be casting everytime.
My question is this: One of the #define
constants I want to make is a power, say ipow(M, T)
, where M
and T
were also #define constants. ipow
is a function in the actual code, so this actually seems to slows things down when I run the code (is it running ipow everytime the constant is mentioned?). However, when I ues the built in pow function and just do (int)pow(M,T)
, the code is sped up. I'm confused as to why this is, since the ipow
and p开发者_JAVA技巧ow
functions are just as fast.
On a more general note, can I define constants using #define
using functions inside the actual code? The above example has me confused on whether this speeds things up or actually slows things down.
(int)pow(M,T)
is faster than using your function ipow
, because if they are doing the same, then ipow
is as fast but with the overhead of calling it (pushing arguments, etc.).
Also, yes, if you #define
it in this way, ipow
/ pow
/ whatever is called every time; the preprocessor has no idea about what it is doing; it's basically string replacing. Therefore, your constant is simply being replaced by the text ipow(M,T)
and so it is calculated everytime you need your constant.
Finally, for your case, a solution might be to use a global variable instead of a #define
constant for your constant. This way, you can compute it once at the beginning of your program, and then use it later (without any more computations of it).
You don't need C++ to do metaprogramming. If you have a C99 compatible C compiler and preprocessor you can use P99 with something like the following
#include "p99_for.h"
#define P00_POW(NAME, I, REC, Y) (NAME) * (REC)
#define IPOW(N, X) (P99_FOR(X, N, P00_POW, P00_NAM, P99_REP(N,)))
For example IPOW(4, A)
is then expanded to ((A) * ((A) * ((A) * (A))))
. The only things that you should watch are
N
must be (or expand to) a plain decimal constant with no suffix such as U or LX
should not have side effects since it is evaluated several times
Yes, ipow is getting run every time the constant is mentioned. The C preprocessor is simply replacing all mentions of the constant with what you #define'd it as.
EDIT:
If you really want to compute these integers at compile time, you could try using Template Metaprogramming. This requires C++, however.
I don't think this is possible with c pre-possessor , because it doesn't support recursion.
(you can use template meta-programming if you are using c++)
I suspect that (int)pow(M,T)
is faster than using (int)ipow(M,T)
because the compiler has special knowledge of the pow()
function (as an intrinsic). I wouldn't be surprised if given constant arguments that it elides the function call altogether when pow()
is used.
However, since it has no special knowledge of ipow()
, it doesn't do the same, and ends up actually calling the function.
You should be able to verify whether or not this is happening by looking at the assembly generated in a debugger or by having the compiler create an assembly listing. If that's what's happening, and your ipow()
function is nothing more than a call to pow()
(casting the result to an int
), you might be able to convince your compiler to perform the same optimization for ipow()
by making it an inline function.
Your ipow isn't faster since its just a simple call to a function. Also I'm aware of compiler optimisation for standard C library routines and math functions.
Most possible the compiler is capable of determining the constexpr parameters and calculate the value of the #define
at compile time.
Internally they will be replaced to some thing like this where the exponent is constant.
#define pow2(x) ( (x) * (x) )
#define pow3(x) ( (x) * (x) * (x) )
#define pow4(x) ( pow2(x) * pow2(x) )
#define pow5(x) ( pow4(x) * (x) )
#define pow6(x) ( pow3(x) * pow3(x) )
...
The only work around is to use C++ metta programming to get better run time performance.
template<class T, T base, T exp>
struct ipow
{
static const T value = base * ipow<T, base, exp - 1>::value;
};
template<class T, T base>
struct ipow<T, base, 0>
{
static const T value = 1;
};
you would use the above struct as follows:
ipow<size_t, M, T>::value
The C preprocessor will not evaluate a function call to a C function such as ipow or pow at compile time, it merely does text replacement.
The preprocessor does have a concept of function-like macros, however these are not so much 'evaluated' as text replaced. It would be temping to think you could write a recursive function-like macro to self-multiply a constant to raise it to a power, but in fact you can't - due to the non-evaluation of macro bodies, you won't actually get continually recursive calculation when the macro refers to itself.
For your shift operation, a #define involving constants and the shift operator will get text replaced by the preprocessor, but the constant expression will get evaluated during compilation, so this is efficient. In fact it's very common in hardware interfaces, ie #define UART_RXD_READY ( 1 << 11 ) or something like that
精彩评论