views:

366

answers:

5

Hi guys,

1) I've got many constants in my C algo. 2) my code works both in floating-point and fixed-point.

Right now, these constants are initialized by a function, float2fixed, whereby in floating-point it does nothing, while in fixed-point, it finds their fixed-point representation. For instance, 0.5f stays 0.5f if working in floating-point, whereas it uses the pow() routine and becomes 32768 if working in fixed-point and the fixed-point representation is Qx.16.

That's easy to maintain, but it takes a lot of time actually to compute these constants in fixed-point (pow is a floatin-point function). In C++, I'd use some meta-programming, so the compiler computes these values at compile-time, so there's no hit at run-time. But in C, thats not possible. Or is it? Anybody knows of such a trick? Is any compiler clever enough to do that?

Looking forward to any answers.

A

+1  A: 

You can ensure compile time initializations in C by using constant expressions.

The following page talks about integral constant expressions, but you should get the deal. http://www.boost.org/development/int_const_guidelines.html

Suvesh Pratapa
A: 

In plain C, there's not much you can do. You need to do the conversion at some point, and the compiler doesn't give you any access to call interesting user-provided functions at compile time. Theoretically, you could try to coax the preprocessor to do it for you, but that's the quick road to total insanity (i.e. you'd have to implement pow() in macros, which is pretty hideous).

Some options I can think of:

  1. Maintain a persistent cache on disk. At least then it'd only be slow once, though you still have to load it, make sure it's not corrupt, etc.

  2. As mentioned in another comment, use template metaprogramming anyway and compile with a C++ compiler. Most C works just fine (arguably better) with a C++ compiler.

Hmm, I guess that's about all I can think of. Good luck.

C Pirate
+1  A: 

When using fixed-point, can you write a program that takes your floating point values and converts them into correct, constant initializers for the fixed point type, so you effectively add a step to the compilation that generates the fixed point values.

One advantage of this will be that you can then define and declare your constants with const so that they won't change at run-time - whereas with the initialization functions, of course, the values have to be modifiable because they are calculated once.


I mean write a simple program that can scan for formulaic lines that might read:

const double somename = 3.14159;

it would read that and generate:

const fixedpoint_t somename = { ...whatever is needed... };

You design the operation to make it easy to manage for both notations - so maybe your converter always reads the file and sometimes rewrites it.

datafile.c:   datafile.constants converter
        converter datafile.constants > datafile.c
Jonathan Leffler
too troublesome. I've got to develop for 6 platforms already, and thats jsut the start.
vectorizor
So, use common code for it - surely, the fixed point stuff is constant across platforms, anyway? Anyway, if it is too troublesome to do it at compile time, then you're likely to have to take the hit at runtime. Good luck. (6 platforms isn't too bad - that's routine for where I work -- and I'm counting Linux on IA32, IA64, Itanium, zLinux, PPC as one platform, not five.)
Jonathan Leffler
well, not to play who's got the biggest :D , but I've got to run on ARM, x86, GPUs ... i.e. vastly, and painfully, different CPUs.Do I win? :)
vectorizor
You may take the win!
Jonathan Leffler
+3  A: 

Rather than using (unsigned)(x*pow(2,16)) to do your fixed point conversion, write it as (unsigned)(0.5f * (1 << 16))

This should be an acceptable as a compile-time constant expression since it involves only builtin operators.

puetzk
very good idea indeed!
vectorizor
A: 

Recent versions of GCC ( around 4.3 ) added the ability to use GMP and MPFR to do some compile-time optimisations by evaluating more complex functions that are constant. That approach leaves your code simple and portable, and trust the compiler to do the heavy lifting.

Of course, there are limits to what it can do, and it would be hard to know if it's optimizing a given instance without going and looking at the assembly. But it might be worth checking out. Here's a link to the description in the changelog

Chris Arguin
But it would be portable only to the point where the compiler you are porting to supports the same optimizations. Otherwise it may compile for the other platform but runtime performance might be unacceptable. Imagine porting something like this to an embedded system with a compiler that does not support the advanced GCC optimizations.
VoidPointer