首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++编译器能识别2的幂吗?

C++编译器能识别2的幂吗?
EN

Stack Overflow用户
提问于 2012-12-18 13:51:27
回答 6查看 656关注 0票数 3

我正在构建一个自定义散列,其中我根据公式对字符串中的所有字母进行求和:

代码语言:javascript
复制
string[0] * 65536 + string[1] * 32768 + string[2] * 16384 + ...

我遇到了一个问题:是否应该将这些数字定义为int数组中的常量:

代码语言:javascript
复制
const int MULTIPLICATION[] = {
    65536,
    32768,
    16384,
    8192,
    4096,
    2048,
    1024,
    512,
    256,
    128,
    64,
    32,
    16,
    8,
    4,
    2,
    1
}

或者,也许我应该在计算散列本身时生成这些数字(同时可能由于没有生成这些数字而失去了一些速度)?我需要数数这个散列数数百万次,我想要编译器理解的主要事情是,而不是正常的MUL操作

代码语言:javascript
复制
MOV EBX, 8
MUL EBX

它就够了

代码语言:javascript
复制
SHL EAX, 3

编译器是否明白,如果我乘2的幂来移位位,而不是通常的乘法?

另一个问题,我很肯定,当您用c++数字*= 2编写时,它确实会移动位,但只是为了澄清,是吗?

谢谢,我已经找到了如何在调试器中查看显示组件。是的,编译器确实理解转换位,如果您使用它的话

代码语言:javascript
复制
number *= 65536

然而,如果你这样做,它会做正常的乘法。

代码语言:javascript
复制
number1 = 65536
number *= number1;
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-12-18 13:53:11

试试看!

你在使用什么编译器?您可以告诉大多数编译器在编译后保留中间文件,或者只编译(而不是汇编),因此您可以实际查看它生成的程序集代码。

您可以在这个我的其他问题上看到,这正是我所做的。

例如,在gcc中,-S标志的意思是“只编译”。而-masm=intel会产生更易读的程序集,IMO。

编辑

总之,我认为下面是您要寻找的算法(未经测试):

代码语言:javascript
复制
// 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有按位旋转指令 (rorrol分别表示右旋转和左旋转)。但是,C没有提供表示旋转操作的方法。所以我定义了ROR宏,它为您执行旋转操作。(理解它的工作原理是留给读者的一项练习!)

在我的循环中,我像你一样在0x10000 (65536)开始乘法器。每次循环的迭代,我把乘法器向右旋转一位。这实际上是将它除以2,直到你得到1,然后它变成0x80000000。

票数 5
EN

Stack Overflow用户

发布于 2012-12-18 13:54:58

答案取决于编译器、硬件体系结构以及可能的其他因素。

用移位代替这种乘法是最理想的做法,这一点在先验上甚至并不明显。我认为,一般来说,应该让指令级的优化编译器。

尽管如此,让我们看看我的编译器是做什么的:)

代码语言:javascript
复制
int i, j;

int main() {
  j = i * 8;
}

使用gcc 4.7.2-O3编译的

代码语言:javascript
复制
_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。中的系数

代码语言:javascript
复制
string[0] * 65536 + string[1] * 32768 + string[2] * 16384 + ...

只需从coeff = 65536开始,每次迭代都向右移动一点:

代码语言:javascript
复制
coeff >>= 1;
票数 3
EN

Stack Overflow用户

发布于 2012-12-18 14:12:07

为什么不直接使用内置在C++中的shift操作符呢?

代码语言:javascript
复制
(string[0] << 16) + (string[1] << 15) + (string[2] << 14) + ...
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13934462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档