C ++编译器是否可以识别2的幂次?
我正在构建一个自定义散列,根据公式对字符串中的所有字母进行求和:
string[0] * 65536 + string[1] * 32768 + string[2] * 16384 + ...
我遇到了一个问题,我是否应该将这些数字定义为int数组中的常量,如下所示:
const int MULTIPLICATION[] = {
65536,
32768,
16384,
8192,
4096,
2048,
1024,
512,
256,
128,
64,
32,
16,
8,
4,
2,
1
}
或者,也许我应该在计算散列本身时生成这些数字(虽然可能由于它们尚未生成而失去一些速度)? 我需要数百万次计算这个散列值,我希望编译器理解的主要事情是代替正常的MUL操作
MOV EBX, 8
MUL EBX
它会这样做
SHL EAX, 3
编译器是否明白,如果我乘以2的幂来移位而不是通常的乘法?
另一个问题,我敢肯定,当你用c ++编号* = 2; 但只是为了澄清,是吗?
谢谢,我已经发现如何在调试器中查看dissasembly。 是的,如果你使用它,编译器会理解移位
number *= 65536
但是,如果你这样做,它会进行正常的乘法运算
number1 = 65536
number *= number1;
尝试一下!
你使用什么编译器? 你可以告诉大多数编译器在编译之后将中间文件放在适当的位置,或者只是编译(而不是汇编),所以你可以看看它生成的汇编代码。
你可以在我的另一个问题上看到,这正是我所做的。
例如,在gcc中-S
标志表示“仅编译”。 -masm=intel
生成更易读的程序集,IMO。
编辑
这一切都说,我认为以下是你正在寻找的算法(未经测试):
// Rotate right by n bits
#define ROR(a, n) ((a >> n) | (a << (sizeof(a)*8-n)))
int custom_hash(const char* str, int len) {
int hash = 0;
int mult = 0x10000; // 65536, but more obvious
for (int i=0; i<len; i++) {
hash += str[i] * mult;
mult = ROR(mult, 1);
}
return mult;
}
首先,你没有指定当你有超过16个字符时会发生什么(什么是乘法器?)所以在这个实现中,我使用了按位旋转。 x86具有按位旋转指令( ror
和rol
用于左右旋转)。 但是,C没有提供表达旋转操作的方法。 所以我定义了为你旋转的ROR
宏。 (了解它是如何工作的,仅供读者参考!)
在我的循环中,我像你一样在0x10000(65536)处启动乘法器。 循环的每次迭代,我将乘数右移一位。 这基本上将它除以2,直到你达到1,之后它变成0x80000000。
答案取决于你的编译器,硬件架构和其他可能的东西。
先验甚至不明显,即用换档来代替这种乘法是最佳的事情。 我认为通常应该让编译器进行指令级优化。
这就是说,让我们看看我的编译器做了什么:)
int i, j;
int main() {
j = i * 8;
}
这是使用gcc 4.7.2
和-O3
编译的结果
_main:
LFB0:
movq _i@GOTPCREL(%rip), %rax
movl (%rax), %edx
movq _j@GOTPCREL(%rip), %rax
sall $3, %edx ;<<<<<<<<<< THE SHIFT INSTRUCTION
movl %edx, (%rax)
ret
所以,在我的环境中,答案显然是“是”。
至于你的其他问题,不要预先计算MULTIPLICATION
。 为了得到系数
string[0] * 65536 + string[1] * 32768 + string[2] * 16384 + ...
只需从coeff = 65536
开始,每次迭代将它向右移一位:
coeff >>= 1;
你为什么不使用C ++中的shift运算符?
(string[0] << 16) + (string[1] << 15) + (string[2] << 14) + ...
链接地址: http://www.djcxy.com/p/31571.html
上一篇: Does C++ compiler recognizes powers of 2?
下一篇: How C# or any other language NOT Equal to operator performs