Reputation: 29106
In algorithms I am using such constants:
sqrt(3)
pow(M_PI, 2)
Unfortunately the C preprocessor is not smart enough to pre-compute these constants. Is there any additional layer of preprocessing that can be used with GCC or any other C compiler?
I have currently implemented these two constants as:
#define SQRT3 1.7320508
#define PIPI (M_PI*M_PI)
But I feel using obscure names like PIPI
(which also means pee in french) is not the best solution. I think it would be better to write:
inline float square(float x) {
return x * x;
}
However this is not possible for the square root. At least, I can get sufficient an approximation with this:
inline float sqrt_approx(float z)
{
int val_int = *(int*)&z;
val_int -= 1 << 23;
val_int >>= 1;
val_int += 1 << 29;
return *(float*)&val_int;
}
Unfortunately, and again, the compiler is not smart enough to interpret sqrt_approx(3)
as 1.73
Is there a better way to deal with these C limitations?
We are in the year 2015, we have rovers that roams on Mars and we are still dealing with C compilers that makes us feel in the 80s. Am I wrong?
Upvotes: 0
Views: 806
Reputation: 5543
Without -ffreestanding
and the like, Gcc computes them at compile-time, at least with optimizations turned on. So there is unlikely to be a function call.
If -ffreestanding
is used, I don't see a better way than defining the constants manually for cases like sqrt
, if a self-made inline function turns out to be insufficiently fast. Gcc's const
attribute may help to avoid re-computations (but I guess Gcc can infere that on its own if the definition is visible).
The question said they should be computed by the preprocessor. I don't see a reason for this, the only thing one can do with floating-point constants in the preprocessor, is to stringify or concatenate them. If this is really needed, they need to be hard-coded, too. An inline function also cannot be called by the preprocessor.
Upvotes: 3
Reputation: 634
Because those constants are true constants (not to be confused with const
variables). You'd want your code to use them directly at runtime, and you certainly do not want to have a call to the sqrt
or pow
function that is basically useless because you already know the result at compile time.
If you want to be sure that there is no useless calls, you should use the macros with C pre-processor for this. And you are not wrong, the C compilers can sometimes make us feel in the 80s. There is many other more modern programming languages available.
However as the compilers are getting more modern at optimizing prorgrams it is also possible that the compiler might inline functions then pre-compute them at compile time. The only way to know if it is possible is to test and look at the generating assembly. For instance in my test program :
static inline int twice(int x)
{
return 2*x;
}
int main()
{
int i = twice(2);
i += twice(4);
printf("Result is %d\n", twice(i));
return 0;
}
Compiles with latest gcc and -Os
turned on to :
main:
sub rsp, 40
.seh_stackalloc 40
.seh_endprologue
call __main
lea rcx, .LC0[rip]
mov edx, 24
call printf
xor eax, eax
add rsp, 40
ret
As you can see, the result, 24 is pre-computed in the assembly code. With double
type it's less obvious to proove because of how floating points number doesn't immediately appear in the assembly, however I checked and the optimisation is also made. Then it is not neccessary to use the C pre-processor for constants anymore. But if you want performance, always check the assembly code.
Upvotes: 1
Reputation: 22154
I would suggest to use constants which makes the compiler aware of it. And pick more explicit names for your constants.
const float SQRT_OF_3 = 1.7320508;
const float PI_SQUARE = M_PI*M_PI;
Upvotes: 1