【问题标题】:Faster comparing signed than unsigned ints [duplicate]比无符号整数更快地比较有符号整数[重复]
【发布时间】:2012-01-09 16:58:36
【问题描述】:

可能重复:
performance of unsigned vs signed integers

我在某处读到,在 x86_64 上比较 C/C++ 中的 signed intsunsigned ints 相比要快一点,例如for (int i...) 比 for (uint i...)“快”。

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

【问题讨论】:

  • 这听起来像是依赖于我的超级平台/编译器......
  • 是的,你是对的——我担心x86_64
  • @Chris:只是部分,我不仅对除法感兴趣。
  • 但许多其他答案和 cmets 中的讨论涵盖除除法之外的其他领域。值得阅读所有答案以获得全貌,因为我认为这已经涵盖在那里。特别是请参阅stackoverflow.com/a/4712784/130352,了解为什么 for 循环中的 unsigned 可能更快(对于更快的可能非常小的值)。
  • 我之前的评论应该说“为什么在 for 循环中 signed 可能会更快。”。 (因为编辑 cmets 的宽限期已过,所以不允许我编辑它)。

标签: c++ c performance gcc


【解决方案1】:

你最好为这种说法引用一个来源,表面上看这很荒谬。

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

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

现在,对于特定的编译器,当面向 x86_64 平台时,一种数据类型的代码生成可能比另一种数据类型更差。但这将是一个非常特殊的情况,不太可能适用于所有 x86_64 编译器。而且,我仍然怀疑缓存效果或后台进程正在影响性能测量(即使是测量每个进程花费的时间的性能计数器也会受到上下文切换使缓存失效的影响)。

【讨论】:

  • 我可以看到至少三种可能受有符号/无符号差异影响(一种或另一种)的优化:考虑到先前计算的附加结果,强度降低(替换除法)例如通过转变,但我没有看到比较的这种效果),值范围传播(确定可能的值范围并使用它来简化代码)。它们中的每一个都非常依赖于上下文。
【解决方案2】:

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

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

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

【讨论】:

  • 虽然这是一个有趣的极端案例,但我仍然认为不是 comparison 更快。​​
【解决方案3】:

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

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

【讨论】:

  • 不正确。一条指令适用于所有人:零扩展 (movzx)、符号扩展 (movsx) 和简单的 mov
  • 这是int_fast32_tint 的参数,如果有的话。
  • 这取决于数据的来源。如果你从内存中读取 32 位,你确实可以使用movsx。但如果你有一个 32 位寄存器中的值,你需要先签署扩展。最重要的是,这取决于。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    测量

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-19
      • 2017-07-27
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2021-03-28
      相关资源
      最近更新 更多