签名比无符号整数更快

可能重复:
无符号vs有符号整数的性能

我已经读过某个地方,在x86_64用比较无signed intsC/C++中的有unsigned ints来比较快,例如for (int i... )比for (uint i...) “更快”。

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

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

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

我更可能认为两种类型的比较之间存在轻微的功率差异,但不是速度差异。

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

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

 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进行签名扩展。 这需要额外的指令。

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

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

我不确定这个符号扩展是否需要简单的for (i=0; i

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

测量

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