简体   繁体   中英

C 'generics' — double and float

I have a function in C that accepts and returns a double (and uses several doubles internally). Is there a good way to make a second version of the function, just like it except with float in place of double ? Also constants like DBL_EPSILON should be updated.

I suppose I could do this with the preprocessor, but that seems awkward (and probably difficult to debug if there's a compile error). What do best practices recommend? I can't imagine I'm the only one who's 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 which is very sensitive to precision in this case; the cost of using doubles rather than floats is 200% to 300%. Up until now I only needed a double version -- when I needed it I wanted as much precision as possible, regardless of the time needed (in that application it was a tiny percentage). But now I've found a use that is sensitive to speed and doesn't benefit from the extra precision. I cringed at my first thought, which was to copy the entire function and replace the types. Then I thought that a better approach would be known to the experts at SO so I posted here.

don't know about "best practices", but the preprocessor definitely was the first thing to jump to my mind. it's similar to templates in C++.

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

you create a separate source file with your functions, everywhere you have a double change it to FLOATING_POINT_TYPE (just as an example) and then include your source file twice from another file. (or whatever method you choose you just need to be able to ultimately process the file twice, once with each data type as your define.) [also to determine the character appended to distinguish different versions of the 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 headers.

but, so in your header file you would need something something like:

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

and for your function definitions/prototypes:

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

and so forth.

i'll definitely leave it to someone else to talk about best practices:)

BTW for an example of this kind of strategy in a mature piece of software you can check out FFTW (fftw.org), although it's a bit more complicated than the example i think it uses basically the same strategy.

Don't bother.

Except for a few specific hardware implementations, there is no advantage to having a float version of a double function. Most IEEE 754 hardware performs all calculations in 64- or 80-bit arithmetic internally, and truncates the results to the desired precision on storing.

It is completely fine to return a double to be used or stored as a float . Creating a float version of the same logic is not likely to run any faster or be more suitable for much of anything. The only exception coming to mind would be GPU-optimized algorithms which do not support 64+ bit operations.

As you can see from most standard librarys and such methods aren't really overridden just new methods are created. For example:

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

A lot of them have different last letters in the method to indicate that it is sort of like a method override for different types. This also applies for return types such as the function atoi, atol, atof.... etc.

Alternatively wrap your function in a macro that adds the type as an argument such as

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

This way it's much easier as you can now just wrap everything with your type avoiding copy pasting the function and you can always check type.

In this case I would say the best practice would be writing a custom codegen tool, which will take 'generic' code and create new version of double and float each time before compilation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM