【问题标题】:gsl_complex vs. std::complex performancegsl_complex 与 std::complex 性能
【发布时间】:2013-09-07 09:59:51
【问题描述】:

我正在编写一个很大程度上依赖于复杂加法和乘法的程序。我想知道我应该使用gsl_complex 还是std::complex

我似乎没有在网上找到 GSL 复数算术与 std::complex 相比要好多少的比较。一个基本的谷歌搜索也没有帮助我找到 GSL 复合体的基准页面。

我编写了一个 20 行的程序,它生成两个随机复数数组(其中 1e7 个),然后使用来自 <ctime>clock() 检查加法和乘法需要多长时间。使用这种方法(没有编译器优化)我知道gsl_complex_addgsl_complex_mul 的速度几乎分别是std::complex<double>+* 的两倍。但是我以前从来没有做过这种事情,所以这就是你检查哪个更快的方式吗?

任何链接或建议都会有所帮助。谢谢!

编辑:

好的,所以我再次尝试使用 -O3 标志,现在结果非常不同! std::complex<float>::operator+ 的速度是 gsl_complex_add 的两倍多,而 gsl_complex_mul 的速度大约是 std::complex<float>::operator* 的 1.25 倍。如果我使用 double,gsl_complex_addstd::complex<double>::operator+ 快大约 30%,而 std::complex<double>::operator*gsl_complex_mul 快大约 10%。我只需要浮点级别的精度,但我heard double 更快(而且内存对我来说不是问题)!所以现在我真的很困惑!

【问题讨论】:

  • 有优化吗?
  • 无论结果如何,您的基准测试几乎肯定被打破了。基准测试很难 ;-)
  • 不,没有(就像我在问题中提到的那样)。
  • @delnan 好吧,也许我的意思并不是技术意义上的基准测试!我如何确定我应该使用什么?这张支票够好吗?
  • 你能分享你的基准测试代码吗?

标签: c++ complex-numbers gsl


【解决方案1】:

开启优化。

您链接的任何库或函数集都将被编译优化(除非开发人员的名字是 Kermit、瑞典厨师、Peggy 小姐(项目经理)和 Cookie Monster(测试员) - 换句话说,开发团队是一群木偶)。

由于std::complex 使用模板,它是由你给的编译器设置编译的,所以代码不会被优化。所以你的问题真的是“为什么函数 X 比做同样事情的函数 Y 快,当函数 X 是用优化编译的而 Y 是在没有优化的情况下编译的?” - 这应该很明显回答:“优化几乎一直有效!” (如果大多数时候优化都不起作用,编译器开发人员会轻松得多)

编辑:所以我的上述观点刚刚被证明。请注意,由于模板可以内联代码,它通常比外部库更有效(因为编译器可以直接将指令插入流程中,而不是调用另一个函数)。

至于floatdoublefloat 唯一比double 慢的情况是只有double 硬件可用,并添加了“缩短”和“延长”两个功能在floatdouble 之间。我不知道有任何这样的硬件。 double 有更多位,因此应该需要更长的时间。

编辑2:

在选择“一个解决方案而不是另一个解决方案”时,有很多因素。性能是其中之一(在某些情况下是最重要的,在其他情况下不是)。其他方面还有“易用性”、“可用性”、“适合项目”等。

如果您只看性能,您有时可以运行简单的基准测试来确定一种解决方案比另一种解决方案更好或更差,但是对于复杂库 [不是“实数和虚数”类型的复数,而是“复杂”],有有时会进行优化以处理大量数据,如果您使用不太复杂的解决方案,“大数据”将无法获得相同的性能,因为在解决“大数据”类型问题上花费的精力较少。因此,如果您有一个“简单”的基准测试,它对一小组数据进行一些基本计算,而实际上您要运行一些更大的数据集,那么小基准测​​试可能无法反映现实。

我或其他任何人都无法告诉您哪种解决方案可以使用您的数据集在您的系统上为您提供最佳性能,除非我们可以访问您的数据集,确切地知道您的计算性能(即是,几乎有你的代码),并且有使用两个“包”运行它的经验。

然后继续其他标准(“易用性”等),这些标准更多地基于“个人意见”,因此首先不适合 SO 问题。

【讨论】:

  • 该信息确实有帮助。但它仍然没有给我一个令人信服的论据来选择一个而不是另一个,正如我目前在我的问题中所指出的那样。我将尝试更多测试并重新编辑。
  • “帮我选择一个解决方案”是一个基于意见的答案,因为几乎从来没有真正的技术答案对特定解决方案说“是”或“否”。您必须根据自己认为的最佳解决方案来选择其中一个,而不是要求 SO。
  • 我明白了。我想我希望答案会像“我应该使用 numpy 向量运算还是 for 循环来对 python 中的两个大数组求和?”一样明确,给出一个粗略的类比。我会听取你的建议。
  • @Praveen:我在回答中添加了更多内容。我仍然认为我们不能对“我应该选择哪个?”给出一个好的答案。类型的问题。技术方面的东西,例如“使用基准时使用优化”,是的,绝对是。但“哪个更适合我”不是其中之一——因为即使您向我们发送了一个完整的基准测试,其中包含您可能使用的数据的准确表示,我的机器可能比您计划使用的机器具有更好或更差的性能使用,扭曲结果。
  • 所以我最终测试了一个包含 4500 个元素的数组(我在程序中使用的数字),并平均了程序运行 1e5 次所花费的时间,包括加法和乘法。我打开了 -O3 和 -ffast-math,因为我不太注重准确性。事实证明,std::complex 和 gsl_complex_float(具有基于 gsl_complex_add 和 gsl_complex_mul 的自定义加法和乘法函数)的价格大致相同。所以我选择 std::complex 是为了便于实施。感谢大家的帮助!
【解决方案2】:

这个答案不仅取决于优化标志,还取决于用于编译 GSL 库和您的特定代码的编译器。示例:如果您使用 gcc 编译 gsl 并使用 icc 编译程序,那么您可能会看到(显着)差异(我已经使用 std::pow 与 gsl_pow 进行了此测试)。此外,./configure 生成的标准 makefile 不会编译具有激进浮点优化的 GSL(例如:它不包括 gcc 中的快速数学标志),因为某些 GSL 例程(例如微分方程求解器)在以下情况下无法通过严格的精度测试存在这些优化。

GSL 的一大优点是库的模块化。如果您不需要双精度,那么您可以使用积极的浮点数优化分别编译gsl_complex.hgsl_complex_math.hmath.c(但是您需要删除math.c 中的#include <config.h> 行)。另一种策略是使用积极的浮点数优化编译整个库的单独版本,并测试准确性是否不是您的特定问题的问题(这是我最喜欢的方法)。

编辑:我忘了提到gsl_complex.h 也有gsl_complex 的浮动版本

typedef struct
  {
    float dat[2];
  }
gsl_complex_float;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 2012-06-30
    相关资源
    最近更新 更多