优化:为什么<比倍数还贵

Optimization: why is < more expensive than multiple !=

本文关键字:为什么 lt 优化      更新时间:2023-10-16

我有一个2d字符数组,需要对其进行一些操作。在某些情况下,我需要检查字符是否为a-h。我过去常常通过检查这个字符是否与其他任何字符都不相等(只有5个其他字符)来实现这一点。然而,我最近有了一个想法,我可以检查角色是否&ltj’获得相同的结果,希望汇编指令更少。

我认为,在某些地方,它确实导致了小幅的加速,但在其他地方,它导致了相当大的减速。有什么想法吗?的相对费用是多少与<在if语句中?

下面是一个示例代码片段:

if( arr[r][c] == arr[r][c+1] && arr[r][c] == arr[r][c+2]
         && arr[r][c] != 'q' && arr[r][c] != 'r' && arr[r][c] != 's' && arr[r][c] != 't')

if( arr[r][c] == arr[r][c+1] && arr[r][c] == arr[r][c+2]
         && arr[r][c] < 'j')

如果我正确理解您的问题,那么您似乎希望检查数组列的所有元素是否都在字符"a"answers"h"之间并且相同,并且您希望优化此过程。

如果你碰巧知道一些汇编语言,我强烈建议你使用反汇编程序来了解函数在执行过程中到底发生了什么。所有编译器和优化级别略有不同。然而,对内存中的两个值进行比较的最低操作包括:

将存储器中的两个变量加载到处理器寄存器(几个时钟周期)

对两个寄存器中的值执行相等测试(1个时钟周期)

基于标志寄存器(英特尔处理器)执行跳转命令(另一个时钟周期)

现在,这是一个与处理器一样简单的操作,但由于您有堆叠的比较操作,这些检查所需的时间会累积(尤其是内存访问所需的时钟周期)

因此,为了减少这些比较所需的时间,需要减少比较的次数。请记住,字符"a"到"h"的ascii值介于0x61和0x68之间(十进制97到104)。您可以通过以下三种比较操作来确定字符是否介于"a"到"h"之间:

if(arr[r][c] >= 97 && arr[r][c] <= 104)

只检查列中的一个值,并使用这种比特旋转技巧来确定列中的所有元素是否相同:

if(((arr[r][c] ^ arr[r][c+1]) + (arr[r][c] ^ arr[r][c+2]) + ...*etc*) == 0)

"xor"("^")比较需要一个时钟周期,加法也是如此,如果任何两个列实体之间存在任何不同,则运算将导致非零结果。此方法的线性时间应随着列元素的数量而增加,作为额外的奖励,优化编译器可能能够在操作期间将"arr[r][c]"保留在其中一个寄存器中。

现代编译器/CPU使用分支预测来预取有利于某些执行路径而非其他执行路径的候选结果。你的汇编预测了不同的结果。结果可能取决于2d数组的内容。此外,在不同的编译器/CPU上,优势可能不同。搜索分支预测-有一些很棒的答案。

不要太关注速度。首先,编写一个程序来解决实际的、有意义的任务。完成后,使用探查器来确定程序的哪些部分是最重要的瓶颈。在你编写了一个程序来解决你实际的、有意义的任务之前,你应该专注于编写可移植的、定义良好的代码,而不是快速的代码。

你对速度的概念不符合C标准。事实上,这里并不能保证速度。有快编译器和慢编译器,甚至有快C解释器和慢C解释器。因此,你关于速度的问题是无效的。如果在这种情况下,你的C编译器不能产生大致相同的代码(就速度而言),那么要么学习如何实现完全优化,要么获得一个新的C编译器。

这看起来不便携:

if( arr[r][c] == arr[r][c+1] && arr[r][c] == arr[r][c+2]
     && arr[r][c] < 'j')

在使用EBCDIC的系统上,假设为1的'j' - 'i'实际上是145 - 137(十二)。你的测试包括11个非字母的额外字符。我建议您在关心性能之前使用strchr("abcdefghi", a[r][c])。如果你担心它的速度(你不应该担心,因为这在解决实际问题的任何事情中都是一项很小的任务),你可以尝试使用开关将其转换为跳转表:

if (arr[r][c] == arr[r][c+1] && arr[r][c] == arr[r][c+2]) {
    switch (a[r][c]) {
        case 'a': case 'b': case 'c':
        case 'd': case 'e': case 'f':
        case 'g': case 'h': case 'i':
        /* XXX: Insert code that runs when a[r][c] is in "abcdefghi"... */
        break;
    }
}

为了衡量这种优化,您可以使用第一段中建议的探查器。