计算小于n

时间:2016-05-15 13:15:00

标签: c bit-manipulation

我正在尝试使用C中的位操作来执行此操作。

From a number n, substract the largest power of 2 smaller than n. 

For example:
6 - 4 = 2
11 - 8 = 3

我的方法是:

next2power = nextHighestPowerOf2(n)
previous2power = next2power >> 1;
result = n - previous2power;

我在nextHighestPowerOf2() v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v |= v >> 32; v++; 中使用了来自Bit Twiddling Hacks的黑客攻击。

next2power

即使我使用unsigned long long,问题仍然是n溢出。 2^64的顺序为1。所以这种方法对我不起作用。

这两种替代方法可以在这里工作:

  1. 将前导0翻转为n
  2. 以某种方式计算2小于n的最高功率而不会溢出,然后从 { folder: true, name: 'D:', children: [ {name: 'Game of Thrones s05e01.avi', size: '1034 mb', type: 'Movie', dateModified: '13/03/2014 10:14'}, {name: 'The Knick s01e01', size: '523 mb', type: 'Text Document', dateModified: '27/11/2012 04:12'}, {name: 'musicbackup1.zip', size: '25 mb', type: 'Compressed Zip File', dateModified: '18/03/2014 00:56'}, {name: 'musicbackup2.zip', size: '25 mb', type: 'Compressed Zip File', dateModified: '18/03/2014 00:56'} ] }
  3. 中减去它

    但我想不出任何解决方案。有没有人知道其他方法来实现这个目标?

5 个答案:

答案 0 :(得分:3)

这应该可以解决您的问题

unsigned long long int res = n - 1ULL<<( (int)log2(n-1) );

当然,当n <= 1

时,你必须设置特殊条件

答案 1 :(得分:2)

如果你有64位int。您需要添加v | = v&gt;&gt; 32复制到低32位。

答案 2 :(得分:2)

虽然n不是2的幂,但请保持关闭设置的最小值。您可以使用n &= (n-1);进行后一种操作(考虑一下)。

在C99中表达:

#include <stdio.h>

int f(int n) {
    while (n & (n-1)) { // n is *not* a power of two
        n &= (n-1);
    }

    return n;
}

int main() {
    for (int n = 1; n < 130; ++n) {
        printf("%d : %d\n", n, f(n));
    }
}

这样做的好处是运行时间与设置的位数成正比。

示例输出:

blazs@blazs:/tmp$ ./x
1 : 1
2 : 2
3 : 2
4 : 4
5 : 4
6 : 4
7 : 4
8 : 8
9 : 8
10 : 8
11 : 8
12 : 8
13 : 8
14 : 8
15 : 8
16 : 16
17 : 16
18 : 16
19 : 16
20 : 16

答案 3 :(得分:0)

取最高设置位几乎总是有效,这很容易:

v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;  // you need this line for 64bit numbers
v &= ~(v >> 1);

但并非总是如此。如果n已经是2的幂,则其最高设置位等于其自身,不小于。所以把v--放在后面。

FWIW,只要你有一个正确的内置方法来获取整数日志(bsr或等价物),记录和移位可能会更快。 FP日志可能是一场灾难。

ps:这些都没有经过测试。

答案 4 :(得分:0)

我认为你在进入或打印你的价值观时可能会犯错误;你问题中的代码对我有用:

#include <stdio.h>
int main() {
        unsigned long long input, v;

        input = 7597026128958891522ULL;
        v = input;
        v--;
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16; 
        v |= v >> 32; 
        v++;
        v= v>>1;
        printf("Input %llu, next lower power of 2 %llu\n", input, v); 
}

产生

Input 7597026128958891522, next lower power of 2 4611686018427387904