我正在用C开发一个专用数学函数库.我需要为库提供一个处理单精度和双精度的功能.这里重要的一点是"单个"函数应该在内部使用"单个"算术(对于"双"函数).
作为示例,请看一下LAPACK(Fortran),它提供了每个函数的两个版本(SINGLE和DOUBLE).还有C数学库(例如,expf和exp).
为了澄清,我想支持类似于以下(人为)示例的内容:
float MyFloatFunc(float x) {
return expf(-2.0f * x)*logf(2.75f*x);
}
double MyDoubleFunc(double x) {
return exp(-2.0 * x)*log(2.75*x);
}
Run Code Online (Sandbox Code Playgroud)
我考虑过以下方法:
使用宏作为函数名称.这仍然需要两个独立的源代码库:
#ifdef USE_FLOAT
#define MYFUNC MyFloatFunc
#else
#define MYFUNC MyDoubleFunc
#endif
Run Code Online (Sandbox Code Playgroud)将宏用于浮点类型.这允许我在两个不同版本之间共享代码库:
#ifdef USE_FLOAT
#define NUMBER float
#else
#define NUMBER double
#endif
Run Code Online (Sandbox Code Playgroud)刚开发两个独立的库,忘记尝试保存头痛.
有人有推荐或其他建议吗?
对于多项式近似,插值和其他固有近似数学函数,您不能在双精度和单精度实现之间共享代码,既不会在单精度版本中浪费时间,也不会在双精度版本中浪费时间. .
然而,如果你走单个代码库的路线,下面的代码应该适用于常量和标准库函数:
#ifdef USE_FLOAT
#define C(x) x##f
#else
#define C(x) x
#endif
... C(2.0) ... C(sin) ...
Run Code Online (Sandbox Code Playgroud)
(部分灵感来自Pascal Cuoq的答案)如果你想要一个具有float和双重版本的库的库,你可以将递归#includes与宏结合使用.它不会产生最清晰的代码,但它确实允许您对两个版本使用相同的代码,并且混淆足够薄,它可能是可管理的:
mylib.h:
#ifndef MYLIB_H_GUARD
#ifdef MYLIB_H_PASS2
#define MYLIB_H_GUARD 1
#undef C
#undef FLT
#define C(X) X
#define FLT double
#else
/* any #include's needed in the header go here */
#undef C
#undef FLT
#define C(X) X##f
#define FLT float
#endif
/* All the dual-version stuff goes here */
FLT C(MyFunc)(FLT x);
#ifndef MYLIB_H_PASS2
/* prepare 2nd pass (for 'double' version) */
#define MYLIB_H_PASS2 1
#include "mylib.h"
#endif
#endif /* guard */
Run Code Online (Sandbox Code Playgroud)
mylib.c:
#ifdef MYLIB_C_PASS2
#undef C
#undef FLT
#define C(X) X
#define FLT double
#else
#include "mylib.h"
/* other #include's */
#undef C
#undef FLT
#define C(X) X##f
#define FLT float
#endif
/* All the dual-version stuff goes here */
FLT C(MyFunc)(FLT x)
{
return C(exp)(C(-2.0) * x) * C(log)(C(2.75) * x);
}
#ifndef MYLIB_C_PASS2
/* prepare 2nd pass (for 'double' version) */
#define MYLIB_C_PASS2 1
#include "mylib.c"
#endif
Run Code Online (Sandbox Code Playgroud)
每个文件#include本身在第二遍中使用不同的宏定义一次,以生成使用宏的代码的两个版本.
但是,有些人可能会反对这种方法.