Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C 'generics' -- double and float

Tags:

c

types

dry

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.

like image 275
Charles Avatar asked Aug 11 '11 02:08

Charles


2 Answers

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.

like image 92
shelleybutterfly Avatar answered Sep 23 '22 20:09

shelleybutterfly


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.

like image 39
wallyk Avatar answered Sep 23 '22 20:09

wallyk