签名比无符号整数更快

时间:2012-01-09 16:58:37

标签: c++ c performance gcc

  

可能重复:
  performance of unsigned vs signed integers

我已经在某个地方读到x86_64signed ints相比C/C++unsigned ints进行比较的速度要快一点,例如for (int i...for (uint i...))比{{1}}“更快”。

这是真的吗?为什么这是真的?我知道差异很小,但无论如何。

5 个答案:

答案 0 :(得分:4)

你最好引用这种说法的来源,这在表面上是荒谬的。

我们谈论的是x86_64,这意味着现代处理器。这些ALU将在单个时钟周期内完成整数加法,减法和/或比较(高速缓存未命中当然需要更长时间,但仅取决于数据的大小和存储器布局,而不是有符号的)。甚至更少,使用SIMD协处理器。

我更有可能相信这两种比较之间存在轻微的功率差异,但不是速度差异。

现在,对于特定的编译器,有可能在针对x86_64平台时,一种数据类型与另一种数据类型的代码生成更糟糕。但这将是一个非常专业的案例,并不太可能适用于所有x86_64编译器。而且,我怀疑缓存效果或后台进程正在影响性能测量(即使是用于测量每个进程花费的时间的性能计数器也会受到使缓存无效的上下文切换的影响)。

答案 1 :(得分:3)

嗯,这里没有好的答案。速度差异通常很小,以至于你花时间考虑其他事情可以获得更好的性能。但是有一些奇怪的情况,因为签名溢出是未定义的。例如,比较这两个:

for (int i = 0; condition(); ++i) {
    if (i == 0) {
        computation();
    }
}

for (unsigned i = 0; condition(); ++i) {
    if (i == 0) {
        computation();
    }
}

符合条件的编译器可以将computation移动到使用带符号索引的循环之外,因为它可以假设i == 0一次且只有一次 - 因为签名溢出是未定义的行为(溢出可能会终止程序,或环绕,或让恶魔飞出你的鼻子)。但是,编译器无法在第二个循环之外移动computation而没有明显更多的工作(无符号整数在溢出时始终会回转)。

但是,在x86_64上,在使用它之前,您经常需要对int进行签名扩展。这需要额外的指示。

结论:这并不重要。无论谁告诉你,一个人比另一个人更快,会分散你的注意力。

答案 2 :(得分:1)

在某些情况下,有符号整数会强制编译器对它们进行签名扩展 如果将整数移动到eax,则rax的高位将设置为零(低位是eax的位)。如果它是整数,则需要将高32位设置为低32位的符号。这是一条额外的指令。

我不确定简单的for (i=0; i<MAX; i++)中是否需要此符号扩展名。

答案 3 :(得分:0)

<强>测量

平台上的测量一直是回答这类问题的唯一方法(而x86_64只是确定平台的起点,可能需要精确的模型)。如今,在芯片上进行的优化(查看“超标量乱序处理器与推测性执行”意味着什么)和编译器会产生这些差异(假设它们存在,我不是真的用于签名/无符号比较,但是像值范围传播和强度降低这样的优化可能会产生影响)因此上下文依赖于需要在所需上下文中进行测量,因为它会对结果产生影响(我已经将代码放在一起使得一些整数变量为double使其执行在某些机器上更好,在其他机器上更糟糕。)

答案 4 :(得分:0)

速度应该没有区别。 x86 32/64上的比较指令(CMP)在有符号和无符号整数数据类型上是相同的。 所有分支指令(jxx)和条件移动(cmovxx)都通过测试CMP更改的CPU标志来工作。 整数数据的增量,减量,成瘾,减法也不知道有符号或无符号数据类型(由于2补码)。