【问题标题】:What is faster in c++? Math calculations or assignment?c++中什么速度更快?数学计算或作业?
【发布时间】:2015-06-01 05:53:38
【问题描述】:

我有这种平静的代码,我想尽可能快地完成它。

我不是一个经验丰富的 c++ 开发人员,所以我很想知道你们是否想出了一些非常好的重新实现该算法,因为我删除了所有的作业,认为这是一件好事......

现在我真的不知道这是否是最好的做法。

那么,什么更快?

for(register uint pPos = 0; pPos < size; pPos++) {
    img->setPixel(pPos % dst_w, pPos / dst_w,
                  buffer32[
                  sf * (
                    (pPos / dst_w * src_w) +
                    (pPos % dst_w)
                  )
            ]);
}

for(register uint pPos = 0, x = 0, y = 0; pPos < size; pPos++) {
    x = pPos % dst_w;
    y = pPos / dst_w;
    img->setPixel(x, y,
                  buffer32[
                  sf * (
                    (y * src_w) + x
                  )
            ]);
}

旁注:我真的认为这是一件好事,我不明白反对票。

也感谢大家的cmets,学到了很多。

【问题讨论】:

  • 编译器优化会使它们相等的机会很大(但理论上没有任何优化,第二个代码可能更快,因为与 1x 和赋值相比,2x 除法和取模非常慢。“可能”因为它取决于很多事情......)
  • 旁注:寄存器已过时
  • 你是用 C++ 编写的,而不是汇编程序,不要试图通过使用 register 或移动简单的算术运算来超越你的编译器。
  • 测量它。不要猜测(如果它真的那么重要。如果不是,请选择最易读的版本)。
  • 在 for 循环中声明不用于循环逻辑的局部变量是不常见的。

标签: c++ image-scaling


【解决方案1】:

哪个更快完全取决于编译器,事实上大多数优化编译器在编译期间基本上会将您的第二个版本转换为您的第一个版本。即使他们不这样做,在现代计算机上,除法运算也只需要几纳秒,因此除非您执行该运算数百万或数十亿次,否则它在您的应用程序中可能并不重要。

在所有这样的情况下,答案都是:

  1. 不用担心,除非某些东西比你想要的慢
  2. 如果某些事情比您想要的要慢,请使用分析器来找出导致问题的确切原因。

编辑

我自己用这个编译器试了一下:

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix

使用此编译器,您的代码将编译为与 g++ -S -O1 完全相同的 ASM 输出。因此,最基本的编译器优化使这个问题变得毫无意义。如果您想让它尽可能快,请使用编译器的优化标志,不要再担心代码了。

【讨论】:

  • 我应该提到“大小”变量的值是图像的像素数量吗?而且这种代码和平每 33.3 毫秒调用一次?
  • @RafaelLucio 在我看来,我可以告诉你,两个代码示例之间的速度没有明显差异,每 33.3 毫秒或 3 毫秒一次。
  • 现代 CPU 每秒可以处理 1000 亿条指令。 1080p 图像有 200 万像素。因此,添加两个操作将每帧增加大约 20 微秒。这不到您的时间限制的 0.1%。因此,仅通过粗略的计算,担心是没有意义的。当然,正如我所提到的,任何体面的编译器都会优化您提供的代码,从而完全没有区别,即使是我刚刚描述的无关紧要的代码。
【解决方案2】:

最低级别的简单赋值比乘法或加法更快。

一些处理器的指令可以在一条指令中执行乘法或加法和赋值。

在寄存器之间退一步、赋值和算术运算比在内存中执行运算要快。访问缓存通常比片上内存快。数据距离处理器内核越远,访问速度就越慢。与包含处理器的同一块硅片上的内存相比,访问芯片外的内存要慢一些。

更快的含义
所以我们知道哪些操作更快。经常被忽视的问题是:

  • 快多少?
  • 获得了多少时间?

让我们假设一个处理器:

  • 分配花费 20 纳秒。
  • 添加需要 50 纳秒。
  • 乘法需要 100 纳秒。

因此,加法运算和赋值之间的“节省”时间为 30 纳秒。乘法运算和加法运算之间的节省时间为 50 纳秒。请记住,用户无法区分小于 1E-2 秒的任何内容。那么,需要多少次迭代才能使 50 纳秒变得明显?

对于现代处理器,必须执行大量迭代才能从这些指令级别更改中获得大量时间。所以投资回报(优化这些指令所花费的时间)是不值得的。只有当程序性能影响销售或需求(例如关键系统)时,投资回报率才会很高。

【讨论】:

  • 这正是我想要的...谢谢!我的目标是一种需要高性能和最低 CPU 使用率的关键系统,同时还要平衡质量。
  • 你应该拿出汇编语言规范和数据表来显示每条指令的时钟周期。
  • 您正在假设 C++ 分配被翻译成哪些处理器指令。做出这些假设的理由并不多。您不能做出诸如“分配花费 20 纳秒”之类的语句,因为特定语句可能会被优化掉,或者本地可能会被放入寄存器中,或者谁知道还有什么。C++ 分配可能是 NO-OP 或重要的时间取决于特定的处理器和特定的编译器。
  • 请注意,当您使用g++ -S 生成没有其他标志的 asm 文件时,默认优化将生成 完全相同的代码,并像这样提取本地代码。因此,在忽略编译器的情况下谈论汇编是非常具有误导性的。
  • 注意:从处理器的低级角度来看,赋值操作比算术操作要快。加法运算比乘法运算快。不管编译器如何翻译代码。是的,编译器可能会消除代码,或者将代码转换为使用寄存器而不是内存。我的回答是基于我在第一段中所说的低层次观点。
【解决方案3】:

第一个比较慢,因为您要多次执行相同的计算。虽然它可能花费的时间可以忽略不计。除非您的代码执行这些操作数千次甚至更多次,否则您不会注意到任何改进。更多的是你的编译器可以优化代码来做到这一点!

使用分析器,那里有很多免费的。您将非常了解操作/功能所花费的时间。

查看此General C++ Performance Improvement Tips 和许多此类链接,了解可帮助您提高编码标准的标准做法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 2016-01-26
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多