优化循环内的重复模数

时间:2012-06-15 19:32:50

标签: c optimization bitwise-operators

我在我的c程序中有这个声明,我想优化。通过优化,我特别想要引用按位运算符(但任何其他建议也很好)。

uint64_t h_one = hash[0];
uint64_t h_two = hash[1];
for ( int i=0; i<k; ++i )
{
    (uint64_t *) k_hash[i] = ( h_one + i * h_two ) % size;   //suggest some optimization for this line.
} 

任何建议都会有很大帮助。

编辑: 截至目前size可以是任何int,但它不是问题,我们可以将其四舍五入到下一个素数(但可能不是2的幂,因为较大的值2的幂增加迅速而且会导致记忆的浪费很多)

h_two是64位int(基本上是64字节的chuck)。

2 个答案:

答案 0 :(得分:4)

基本上你正在做

k_0 = h_1 mod s
k_1 = h_1 + h_2 mod s = k_0 + h_2 mod s
k_2 = h_1 + h_2 + h_2 mod s = k_1 + h_2 mod s
..
k_n = k_(n-1) + h_2 mod s

根据溢出问题(如果大小小于2**64的一半,则不应与原始问题不同),这可能会更快(虽然不太容易并行化):

uint64_t h_one = hash[0];
uint64_t h_two = hash[1];
k_hash[0] = h_one % size;
for ( int i=1; i<k; ++i )
{
    (uint64_t *) k_hash[i] = ( k_hash[i-1] + h_two ) % size;
} 

请注意,您的编译器可能已经使用此表单,具体取决于您使用的优化标记。

当然这只消除了一次乘法。如果你想消除或减少模数,我想基于h_two%sizeh_1%size你可以预先确定你必须明确调用%size的步骤,如下所示:

uint64_t h_one = hash[0]%size;
uint64_t h_two = hash[1]%size;
k_hash[0] = h_one;
step = (size-(h_one))/(h_two)-1;
for ( int i=1; i<k; ++i )
{
    (uint64_t *) k_hash[i] = ( k_hash[i-1] + h_two );
    if(i==step)
    {
        k_hash[i] %= size;
    }
} 

注意我不确定公式(没有测试它),这是一个更普遍的想法。这在很大程度上取决于您的分支预测有多好(以及错误预测的性能有多大)。如果步骤很大,它也可能会有所帮助。

编辑:或更简单(并且可能具有相同的性能) - 谢谢神秘:

uint64_t h_one = hash[0]%size;
uint64_t h_two = hash[1]%size;
k_hash[0] = h_one;
for ( int i=1; i<k; ++i )
{
    (uint64_t *) k_hash[i] = ( k_hash[i-1] + h_two );
    if(k_hash[i] > size)
    {
        k_hash[i] -= size;
    }
} 

答案 1 :(得分:0)

如果size是2的幂,那么对size - 1应用按位AND优化“%size”:

(uint64_t *)k_hash[i] = (h_one + i * h_two) & (size - 1)