优化:为什么<比倍数还贵
Optimization: why is < more expensive than multiple !=
我有一个2d字符数组,需要对其进行一些操作。在某些情况下,我需要检查字符是否为a-h。我过去常常通过检查这个字符是否与其他任何字符都不相等(只有5个其他字符)来实现这一点。然而,我最近有了一个想法,我可以检查角色是否<j’获得相同的结果,希望汇编指令更少。
我认为,在某些地方,它确实导致了小幅的加速,但在其他地方,它导致了相当大的减速。有什么想法吗?的相对费用是多少与<在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;
}
}
为了衡量这种优化,您可以使用第一段中建议的探查器。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- 为什么字符串流运算符<<擦除原始值
- 当运算符<存在时,为什么要定义 LT?
- 重载& lt; & lt;为什么我得到以下错误