English 中文(简体)
妥善设计处理单一和双重计算浮动点的C码?
原标题:Proper design of C code that handles both single- and double-precision floating point?

我正在C开发一个特殊用途数学功能图书馆。 我需要为图书馆提供处理单一视距和双重视距的能力。 这里的重要一点是,“单一”功能应当使用奥文特内部的“单一”算术(“双重”功能)。

举例来说,请见LAPACK(Fortran),其中提供了每项职能的两个版本(SINGLE和DOUBLE)。 C 数学图书馆(Example,expfexp)。

为了澄清,我要支持类似以下(持续)例子:

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);
}

我对以下做法进行了思考:

  1. 利用宏观方法确定功能名称。 这仍然需要两个单独的源代码基:

    #ifdef USE_FLOAT
    #define MYFUNC MyFloatFunc
    #else
    #define MYFUNC MyDoubleFunc
    #endif
    
  2. 利用宏观处理浮动点类型。 这使我能够分享两个不同版本的编码基础:

    #ifdef USE_FLOAT
    #define NUMBER float
    #else
    #define NUMBER double
    #endif
    
  3. 仅仅开发两个单独的图书馆,并设法挽救头痛。

是否有任何人提出建议或补充建议?

最佳回答

对于多功能的近似、干涉和其他固有的近似的数学功能,你不能在双重计算和单一精度执行之间分享代码,而不必在单一精度版本中浪费时间,或比重复计算时更具有相关性。

然而,如果你走到单一编码基线的路,那么以下工作就是为了履行固定和标准图书馆职能:

#ifdef USE_FLOAT
#define C(x) x##f
#else
#define C(x) x
#endif

... C(2.0) ... C(sin) ...
问题回答

(Partially inspired by Pascal Cuoq s answer) If you want one library with float and double versions of everything, you could use recursive #includes in combination with macros. It doesn t result in the clearest of code, but it does let you use the same code for both versions, and the obfuscation is thin enough it s probably manageable:

<>strong>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 */

<>strong>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

每一文档#include在使用第二份通行证的不同宏观定义时,又一次生成两种使用宏观代码。

Some people may object to this approach, though.

你们要面对的主要问题是:

  • Is it easier to maintain two separate unobfuscated source trees, or one obfuscated one?

如果你有拟议的共同编码,你必须谨慎地起草该守则,不要书写任何未加更正的固定或非常规功能电话(或职能机构)。

If you have separate source code trees, the code will be simpler to maintain in that each tree will look like normal (non-obfuscated) C code, but if there is a bug in YourFunctionA in the float version, will you always remember to make the matching change in the double version.

我认为,这取决于职能的复杂性和波动性。 我怀疑,一旦写成并第一次 de倒,很少需要回头来。 这实际上意味着你使用的机制确实很重要——两者都是可行的。 如果职能机构有些不稳定,或职能清单不稳定,则单一编码基数总体可能比较容易。 如果一切都非常稳定,两个单独的法典基础的清晰度可能更可取。 但它非常主观。

我也许会拿到一个单一的代码基数和墙对墙的宏观。 但我并不认为这是最好的,而另一种方式也有好处。

The <tgmath.h> header, standardized in C 1999, provides type-generic calls to the routines in <math.h> and <complex.h>. After you include <tgmath.h>;, the source text sin(x) will call sinl if x is long double, sin if x is double, and sinf if x is float.

您仍需要确定您的常数,以便您酌情使用<代码>3.1<>/code>或3.1f。 根据你们的需要和你看来更多的美学,这方面有多种合成技术。 对于在<代码>float精确度上准确代表的固定装置,你只能使用浮动表格。 例如,y = .5f * x将自动转换.5fdouble<>code>。 但sin(.5f)将产生sinf(.5f),其准确性低于sin(.5)

您也许能够将有条件化降低到一个单一的明确定义:

#if defined USE_FLOAT
    typedef float Float;
#else
    typedef double Float;
#endif

这样,你就可以以这样的方式使用不变:

const Float pi = 3.14159265358979323846233;
Float y = sin(pi*x);
Float z = (Float) 2.71828182844 * x;

这可能并不完全令人满意,因为很少出现将数字转换为<条码>、杜布莱,然后改为<条码>float<>/代码>,其准确性低于直接转换为<条码>float的数值。 因此,如果有必要,可在<条码>C(>>>上对数字作必要的补充。





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...