我正在构建一个自定义散列,其中我根据公式对字符串中的所有字母进行求和:
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编写时,它确实会移动位,但只是为了澄清,是吗?
谢谢,我已经找到了如何在调试器中查看显示组件。是的,编译器确实理解转换位,如果您使用它的话
number *= 65536然而,如果你这样做,它会做正常的乘法。
number1 = 65536
number *= number1;发布于 2012-12-18 13:53:11
试试看!
你在使用什么编译器?您可以告诉大多数编译器在编译后保留中间文件,或者只编译(而不是汇编),因此您可以实际查看它生成的程序集代码。
您可以在这个我的其他问题上看到,这正是我所做的。
例如,在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。
发布于 2012-12-18 13:54:58
答案取决于编译器、硬件体系结构以及可能的其他因素。
用移位代替这种乘法是最理想的做法,这一点在先验上甚至并不明显。我认为,一般来说,应该让指令级的优化编译器。
尽管如此,让我们看看我的编译器是做什么的:)
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;发布于 2012-12-18 14:12:07
为什么不直接使用内置在C++中的shift操作符呢?
(string[0] << 16) + (string[1] << 15) + (string[2] << 14) + ...https://stackoverflow.com/questions/13934462
复制相似问题