【问题标题】:Is a letter compare slower than number compare?字母比较比数字比较慢吗?
【发布时间】:2011-01-26 10:33:36
【问题描述】:

在这里忍耐一下。

几个月前,我记得我的算法老师和我们讨论了桶排序的实现(在我的算法书中称为分布排序)以及它是如何工作的。基本上,我们不是从表面上取一个数字,而是通过二进制表示进行比较,如下所示:

// 32 bit integers.
Input:  9 4

4: 00000000 00000000 00000000 00000110
9: 00000000 00000000 00000000 00001001
// Etc.

然后从右到左开始比较。

// First step.
4: 0
9: 1

Output: 9 4

// Second step
4: 1
9: 0

Output: 4 9 // Technically a stable algorithm, but we cannot observe that here.

// Third step

4: 1
9: 0

Output: 4 9

// Fourth step

4: 0
9: 1

Output: 9 4

就是这样;其他 28 次迭代都为零,因此输出不会再改变。现在,像这样比较一大堆字符串就可以了

// strings
Input: "Christian" "Denis"

Christian: C h r i s t i a n
Denis:     D e n i s

// First step.
Christian: n
Denis:     s

Output: Christian, Denis

// Second step
Christian: a
Denis:     i

Output: Denis, Christian

// ... 

等等。

我的问题是,比较有符号字符、字节数字是否比比较整数更快?

如果我不得不假设,一个 1 字节的字符比一个 4 字节的整数要快。这个对吗?我可以对 wchar_t 或 UTF-16/32 格式做出相同的假设吗?

【问题讨论】:

  • 这听起来更像基数排序而不是桶排序,并且使用基数 2(基数 2)不是一个好主意。
  • 我喜欢你的导师如何将基本的、恒定的时间比较变成线性比较。我必须承认,我从未考虑过这样做。
  • 真的吗?我还没有真正见过基数排序——我的教授告诉我们他不会和我们一起做那个,因为它们太相似了。第一个例子和他给我们的几乎一模一样。

标签: c++ algorithm


【解决方案1】:

在 C 或 C++ 中,char 只是一个单字节整数(尽管“一个字节”可能是也可能不是 8 位)。这意味着在典型情况下,您必须处理的唯一区别是单字节比较是否比多字节比较快。

至少在大多数情况下,答案是否定的。许多 RISC 处理器根本没有处理单个字节的指令,因此对单个字节的操作是通过将字节符号扩展为一个字,对该字进行操作,然后(如有必要)屏蔽所有单个字节之外的位回零 - 即,对整个字进行操作通常可以是对单个字节进行操作的速度的三倍左右。

即使在像 x86 这样直接支持单字节操作的东西上,它们仍然通常比较慢(在现代处理器上)。有几件事促成了这一点。首先,使用对当前模式“自然”大小的寄存器的指令比使用其他大小的指令具有更简单的编码。其次,相当多的 x86 处理器具有所谓的“部分寄存器停顿”——尽管这都是隐式的,但它们在内部执行类似于 RISC 的操作,对全尺寸寄存器执行操作,然后将其与原始值的其他字节。例如,如果您在 AL 中生成结果然后引用 EAX,则执行序列的时间将比在 EAX 中生成结果开始时更长。

OTOH,如果您查看足够旧的处理器,则相反可能(并且通常是)正确。举一个极端的例子,考虑 Intel 8080 或 Zilog Z80。两者都有一些 16 位指令,但通过 ALU 的路径只有 8 位宽——例如,16 位加法实际上是作为两个连续的 8 位加法执行的。如果你只用一个 8 位操作就可以了,它的速度大约是原来的两倍。尽管 8 位处理器在台式机上是一种(遥远的)内存,但它们仍然用于一些嵌入式应用程序,因此这也不是完全过时的。

【讨论】:

    【解决方案2】:

    单字节字符在 C++ 中作为数字进行比较。具体速度取决于宿主 CPU 平台,通常与比较 4 字节整数的速度相同。

    【讨论】:

      【解决方案3】:

      您不能假设哪种比较更快,这取决于您的特定平台。

      通常,int 是 CPU 最“舒适”的大小,因此比较它们通常是最快的。任何更大的东西都可能更慢,因为它可能需要分解成多个ints。任何较小的可能都与int 一样快,但根据内存架构,未对齐的读取可能需要更长的时间。

      除此之外,还有内存带宽因素。类型越大,所需的带宽就越高。然后是最重要的缓存效果。如果瓶颈是 CPU 速度,那么这无关紧要。否则,它会。

      【讨论】:

      • 是的,根据我的经验,编译器和 CPU 会针对整数运算进行优化。整数值通常在双字/全字/半字边界上对齐,具体取决于值的大小;字节可能是也可能不是字对齐的。根据您的编译器和底层硬件架构,缺少字对齐可能会产生访问成本。
      【解决方案4】:

      我的问题是,比较有符号字符、字节数字是否比比较整数更快?

      没有。在 C++ 中,这些操作的速度肯定是相同的。现代 CPU 以 4 字节为单位执行大多数操作1,因此 1 字节与 4 字节不会减少任何计算时间。

      请假设与整数示例转换为二进制无关

      没有发生任何转换。数字在 PC 中表示为二进制。


      1 大体简化。但为了论证,我们可以声明 C++ 中的 int 始终是给定 CPU 上的“本机”度量单位。

      【讨论】:

      • 从未与自然边界对齐的内存中读取chars 的成本如何?
      • @Oli:在我的回答中没有考虑,原则上是一个好点。但是,无论如何都不会缓存单个字节,所以我不确定这是否会起作用。现在,如果您有跨越对齐边界的多字节值……例如字符串……但这应该(完全)偏移字符串的长度。
      【解决方案5】:

      如果我不得不假设,1 字节的字符比 4 字节的整数要快。这是正确的吗?

      我非常怀疑。如果我在哪里猜测我的赌注将是相反的,如果其中一个比另一个慢。原因?当今的大多数处理器都是为直接处理 4 字节类型而构建的。

      我可以对 wchar_t 或 UTF-16/32 格式做同样的假设吗?

      没有。 UTF 格式涉及更多,不能直接逐字节比较,除非您严格检查是否相等。

      您真的不应该担心这种速度问题。如果您的讲师教您关注比较 1 字节类型与 4 字节类型的速度,那么您真的需要用大量的盐来接受他们所说的一切。编写高效的算法,不要尝试在这种细节级别上进行优化。

      【讨论】:

      • 到一个点。自从 SSE 指令问世以来,很多人都将它们用于 UTF-8 处理(主要是它可以让您测试 16 个字节的输入是否是 7f 或以下的 16 个代码点,比使用单个字节的周期少得多),最多放弃 4 次某些情况下的吞吐量。如果您的算法不能反映您的硬件提供的机会,那么它们就没有相关性。
      【解决方案6】:

      答案是“对齐”。比较未在自然字边界上对齐的字符总是比比较对齐的数据慢。除此之外,处理器在流水线中每个周期执行多个操作,并且许多其他条件都会影响性能。

      【讨论】:

        【解决方案7】:

        正如 Al Kepp 所说,这取决于您的平台。但是,大多数 CPU 都有一个内置指令来比较 Words,因为它是一条 CPU 指令,只要您要比较的数据适合一个字,就总是需要相同的时间。

        CMP x86 Assembly

        【讨论】:

          猜你喜欢
          • 2013-05-06
          • 1970-01-01
          • 2014-07-13
          • 2014-09-13
          • 1970-01-01
          • 2012-03-11
          • 1970-01-01
          • 1970-01-01
          • 2017-04-26
          相关资源
          最近更新 更多