nowox
nowox

Reputation: 29106

What is better, macros or inline functions for square or sqrt of constants?

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

Answers (3)

mafso
mafso

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

Bregalad
Bregalad

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

chmike
chmike

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

Related Questions