C 'generics' - double and float

I have a function in C that takes and returns a double (and uses multiple duplicates inside). Is there a good way to make a second version of a function, just like with a float instead of a double ? It is also necessary to update constants such as DBL_EPSILON .

I suppose I could do this with a preprocessor, but it seems uncomfortable (and probably hard to debug if there is a compilation error). What do the recommendations recommend? I cannot imagine that I am the only one who had to deal with this.

Edit: I forgot, this is stackoverflow, so I can’t just ask a question, I have to justify myself. I have code that is very sensitive to accuracy in this case; the cost of using doubles, rather than floating ones, ranges from 200 to 300%. Until now, I only needed the double version - when I needed it, I wanted as much accuracy as possible, regardless of the time (in this application it was a tiny percentage). But now I have found an application that is sensitive to speed and does not receive additional accuracy. I cringed in my first thought, which was to copy the entire function and replace the types. Then I thought that the best approach would be known to experts in SO, so I posted here.

+4
source share
4 answers

they don’t know about β€œbest practices,” but the preprocessor was definitely the first thing that jumped at me. It is similar to templates in C ++.

[edit: and the answer of Jesus Ramos mentions different letters about functions with different types in libraries, and indeed, you probably want to do this]

you create a separate source file with your functions, everywhere you change it twice to FLOATING_POINT_TYPE (as an example), and then you include the source file from another file twice. (or any other method you choose, you just need to ultimately process the file twice, once with each data type as your definition.) [also to define a character added to distinguish between different versions of a function, define FLOATING_POINT_TYPE_CHAR]

 #define FLOATING_POINT_TYPE double #define FLOATING_POINT_TYPE_CHAR d #include "my_fp_file.c" #undef FLOATING_POINT_TYPE_CHAR #undef FLOATING_POINT_TYPE #define FLOATING_POINT_TYPE float #define FLOATING_POINT_TYPE_CHAR f #include "my_fp_file.c" #undef FLOATING_POINT_TYPE #undef FLOATING_POINT_TYPE_CHAR 

then you can also use a similar strategy for your prototypes in your headings.

but, therefore, in your header file you will need something like:

 #define MY_FP_FUNC(funcname, typechar) \ funcname##typechar 

and for function / prototype definitions:

 FLOATING_POINT_TYPE MY_FP_FUNC(DoTheMath, FLOATING_POINT_TYPE_CHAR) ( FLOATING_POINT_TYPE Value1, FLOATING_POINT_TYPE Value2 ); 

etc.

I will definitely leave it to someone else to talk about the best methods :)

By the way, for an example of such a strategy in the mature piece of software, you can check out FFTW (fftw.org), although this is a little more complicated than the example, I think that it uses basically the same strategy.

+2
source

Do not worry.

With the exception of a few specific hardware implementations, there is no advantage to having a float version of the double function. Most IEEE 754 hardware performs all calculations in 64- or 80-bit arithmetic internally and trims the results to the desired storage accuracy.

It is possible to return a double that will be used or stored as a float . Creating a float version of the same logic is unlikely to be faster or more appropriate for most of everything. The only thing that comes to mind is GPU-optimized algorithms that do not support 64-bit operations.

+2
source

As you can see from most standard libraries, such methods are not overridden, but new methods are created. For instance:

 void my_function(double d1, double d2); void my_functionf(float f1, float f2); 

Many of them have different last letters in the method to indicate that it is like overriding a method for different types. This also applies to return types, such as the atoi, atol, atof .... functions, etc.

Alternatively, transfer your function to a macro that adds the type as an argument, e.g.

 #define myfunction(arg1, arg2, type) .... 

Thus, it is much simpler, because now you can simply wrap everything with your type, avoiding copying, pasting a function, and you can always check the type.

+2
source

In this case, I would say that the best practice would be to create a special tool for code generation, which will take the "common" code and create a new version of double and float every time before compilation.

+2
source

All Articles