gpt4 book ai didi

c - 在 C 中调用常数复数的最快方法

转载 作者:太空宇宙 更新时间:2023-11-04 00:03:13 24 4
gpt4 key购买 nike

我在 C 中使用 GSL 来处理复数。

我不得不多次使用像 +-1、0、+-i 这样的复数(跨不同的函数),我想像 10^9 这样的东西(也许更多,还不知道),所以我需要一种非常快速的方式来调用它们。

在 gsl_complex_math.h 中它们是这样定义的:

#define GSL_COMPLEX_ONE (gsl_complex_rect(1.0,0.0))

在哪里

gsl_complex_rect (double x, double y)
{ /* return z = x + i y */
gsl_complex z;
GSL_SET_COMPLEX (&z, x, y);
return z;
}

#define GSL_SET_COMPLEX(zp,x,y) do {(zp)->dat[0]=(x); (zp)->dat[1]=(y);} while(0)

就我的目的而言,这看起来像是大量的代码和临时变量声明,但我在评估代码效率方面的经验完全为零。

如果我像这样在 global.h 的 header 中声明一个全局变量会怎样:

#if defined MAIN_PROGRAM
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN const gsl_complex C_U = {.dat[0] = 1., .dat[1] = 0.}

1) 我应该期待性能提升吗?2)代码是否足够干净?我要进入任何陷阱了吗?3)有更好的方法吗?

最佳答案

  1. 过早的优化是一件坏事。在您拥有可以进行基准测试(启用编译器优化!)的有效实现之后,这个小的更改很容易实现!

  2. a) 将全局常量用于公共(public)值是(适度)一种干净的编码方式。然而,如果库本身已经提供了这样的常量(或者在这种情况下,看起来像常量的函数),那么使用它们通常会更干净(进入项目的新程序员将立即看到发生了什么,而无需遵循您的自定义定义)

    b) 全局常量的潜在问题是:

    • 变量是被复制还是被引用? (每个人在他们自己的情况下可能会更快,通常取决于结构的大小与指针的大小和取消引用的成本)
    • 这个值真的是常量吗? (一个行为不佳的函数可能会抛弃 const-ness 并尝试更改它,这可能会导致一些延长的调试 session )
    • 您最终可能会得到更糟糕的引用局部性(函数使用的值在内存中的距离会更远,从而导致更少的缓存命中,可能会降低性能)
  3. 对于这么小的对象,构造开销如此之低,没有比您已经知道的两个选项更好的方法了。对于需要花费更多精力来构建的较大对象,具有缓存的工厂模式可能更合适,但此处不适用。


详细说明 (1):

库使用的代码将比您想象的更优化;

  • do...while 是宏定义中的常见模式,任何体面的编译器都会将其完全删除。这只是一种确保多个命令在无括号 if 以及其他地方
  • 中使用时仍能正常运行的方法
  • 该函数可能对其返回值应用了复制省略(即没有临时值,也没有复制),或者甚至是完全内联的(没有临时值,没有复制,也没有函数调用)。由于 C 的 as-if 规则,两者都被允许

这意味着优化后的总成本将是堆栈上的内存空间和 2 个赋值(对于一个好的编译器,如果 2 个赋值可以优化为包含两个值的单个赋值,我不会感到惊讶)。对于较低级别的优化,它还可能涉及函数调用。

所以最后的比较是这样的:

  • 就地构建与复制全局常量:完全优化后,它们是相同的(已使用 Clang 3.7 进行测试和确认)。
  • 就地构建与指向全局常量的指针:根据环境中指针的大小,复制指针可能比创建新对象更快,但由于引用的局部性问题,它的性能可能更差

关于c - 在 C 中调用常数复数的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34382058/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com