C“泛型” -- 双精度和浮点

发布于 2024-11-29 03:32:30 字数 499 浏览 0 评论 0原文

我在 C 中有一个函数,它接受并返回一个双精度数(并在内部使用多个双精度数)。有没有一个好方法来制作该函数的第二个版本,就像它一样,只是用 float 代替 double ?此外,像 DBL_EPSILON 这样的常量也应该更新。

我想我可以用预处理器来做到这一点,但这看起来很尴尬(如果存在编译错误,可能很难调试)。最佳实践推荐什么?我无法想象我是唯一一个必须处理这个问题的人。

编辑:我忘了,这是 stackoverflow,所以我不能只问问题,我必须为自己辩护。在这种情况下,我的代码对精度非常敏感;使用双精度数而不是浮点数的成本是 200% 到 300%。到目前为止,我只需要一个双精度版本——当我需要它时,我想要尽可能高的精度,无论所需的时间如何(在该应用程序中,它只占很小的百分比)。但现在我发现了一种对速度敏感且无法从额外精度中受益的用途。我对我的第一个想法感到畏缩,那就是复制整个函数并替换类型。然后我认为 SO 的专家会知道更好的方法,所以我在这里发布了。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乄_柒ぐ汐 2024-12-06 03:32:30

不知道“最佳实践”,但预处理器绝对是我首先想到的。它类似于 C++ 中的模板。

[编辑:Jesus Ramos 的回答提到了库中不同类型的函数的不同字母,实际上您可能想要这样做]

您使用您的函数创建一个单独的源文件,在任何地方都将其双重更改为 FLOATING_POINT_TYPE (仅作为示例),然后将另一个文件中的源文件包含两次。 (或者您选择的任何方法,您只需要能够最终处理文件两次,一次使用您定义的每种数据类型。)[还要确定附加的字符以区分函数的不同版本,定义 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

然后您可以还在标题中对原型使用类似的策略。

但是,因此在您的头文件中,您需要类似的内容:

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

以及您的函数定义/原型:

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

等等。

肯定将其留给其他人来讨论最佳实践:)

顺便说一句,有关成熟软件中这种策略的示例,您可以查看 FFTW (fftw.org),尽管它比示例更复杂一些,我认为它使用基本相同的策略。

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.

街角迷惘 2024-12-06 03:32:30

别打扰。

除了一些特定的硬件实现之外,使用 double 函数的 float 版本没有任何优势。大多数 IEEE 754 硬件在内部以 64 位或 80 位算术执行所有计算,并将结果截断为存储时所需的精度。

返回一个 double 来使用或存储为 float 是完全可以的。创建相同逻辑的 float 版本不太可能运行得更快或更适合任何事情。我想到的唯一例外是 GPU 优化算法,它不支持 64 位以上的操作。

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.

薯片软お妹 2024-12-06 03:32:30

正如您从大多数标准库中看到的那样,这些方法并没有真正被覆盖,只是创建了新方法。例如:

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

其中许多方法在方法中具有不同的最后一个字母,表明它有点像不同类型的方法重写。这也适用于返回类型,例如函数 atoi、atol、atof... 等。

或者将函数包装在宏中,将类型添加为参数,例如

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

这样,它更容易,因为您现在可以将所有内容包装为您的类型避免复制粘贴函数,并且您可以随时检查类型。

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.

∞琼窗梦回ˉ 2024-12-06 03:32:30

在这种情况下,我想说最好的做法是编写一个自定义代码生成工具,该工具将采用“通用”代码并在每次编译之前创建新版本的 double 和 float 。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文