当前的CPU中,算术运算和条件语句哪个更耗费成本?

6
20-30年前,诸如除法之类的算术操作是CPU中最昂贵的操作之一。在一个重复调用的代码片段中节省一个除法运算可以显著提高性能。但是今天,由于CPU使用指令流水线,条件语句可能会破坏有效的执行,因此CPU具有快速的算术操作。如果我想优化代码以提高速度,我应该优先考虑算术操作而不是条件语句吗?

示例1

假设我们想要实现模n的操作,哪种方法更好:
int c = a + b;
result = (c >= n) ? (c - n) : c;

或者

result = (a + b) % n;

?

例子2

假设我们正在将24位有符号数转换为32位。哪种方法会更有效:

int32_t x = ...;
result = (x & 0x800000) ? (x | 0xff000000) : x;

或者

result = (x << 8) >> 8;

?


2
对于“让编译器处理它”的人群:我向你们挑战,找到一个编译器,可以为示例#1生成相同的代码,给定int a = rand()%n,b = rand()%n; - Ben Voigt
3个回答

3
如果你想优化速度,你应该让编译器去优化速度。现代编译器通常在这方面比你表现得更好。我有时会因为这个原因而惊讶地发现自己试图将汇编代码与原始源代码联系起来。优化你的源代码以便更易读,并让编译器做它最擅长的事情。

3
只有当你没有信息时,编译器才没有。许多优化仅对有限范围的输入有效。如果您知道约束已满足而编译器不知道,则需要自己进行优化。编译器编写者有时根本不会花时间进行这样的转换,仅仅因为它们并非普遍可用。 - Ben Voigt

3
所有易于优化的技术细节都已经被编译器作者和硬件制造商捡走了。如果您需要询问此类问题,那么您可能无法通过手动优化来提高性能。20年前,相对称职的程序员可以通过降低到汇编语言来进行一些优化,但现在这已经成为专家领域,需要针对目标架构而专门化;此外,优化不仅需要了解程序,还需要知道它将处理的数据。所有的一切都归结为试验、不同条件下的测试等启发式方法。简单的性能问题已经没有简单的答案了。

他在这里不写汇编。 - Ben Voigt
1
@BenVoigt: 然而我的回答仍然成立。 - fdreger
2
仅适用于非常底层的东西。使用复杂度更低的算法进行替换仍然是非常可取的优化,而编译器还不能为您完成它。有条件地有效的优化是另一个棘手的问题,程序员必须介入,无论是手动优化还是手动标记前提条件。 - Ben Voigt
2
@BenVoigt:是的,你说得对,但是——根据问题——这些点都不相关。对于这个问题的答案是:“不可能确定,因为不知道确切的CPU、结果将如何在代码中使用、编译器、月相等等。”即使是最简单的提升也可以改变结果。 - fdreger

3
我期望在示例#1中,第一个表现更好。编译器可能会应用一些位操作技巧来避免分支。但你利用的知识是极不可能被编译器推断出来的:即总和始终在范围[0:2*n-2]内,因此单个减法就足够了。
例如#2,第二种方法在现代CPU上既更快,又更容易理解。无论哪个版本都适合适度的注释。(我不会惊讶地看到编译器将第一个版本转换为第二个版本。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接