计算无符号长整数的位数

时间:2016-04-07 14:25:14

标签: c

所以我写了这个函数来计算long中的位数,为了我的目的,它包括MSB右边的零并且在它的左边排除零:

int bitCount(unsigned long bits)
{
    int len = 64;
    unsigned long mask = 0x8000000000000000;
    while ((bits & mask) == 0 && len > 0){
        mask >>= 1;
        --len;
    }
    return len;
}

就返回正确的答案而言,这个功能对我来说很好,但有没有更好的(更快或其他)方式去做这个?

3 个答案:

答案 0 :(得分:0)

如果要计算long类型中的位数,建议您使用<limits.h>头文件中的ULONG_MAX,并使用右移运算符{{1}计算一位的数量。这样您就不必事先知道位数。

这样的东西
>>

这是有效的,因为右移用零填满。

答案 1 :(得分:0)

任何类型的位数的一般答案是CHAR_BIT*sizeof(type)CHAR_BIT中定义的<limits.h>char中的(实现定义的)位数。 sizeof(type)的指定方式会产生用于表示类型的char个数(即sizeof(char)1)。

答案 2 :(得分:0)

其他人提出的解决方案非常好,可能是最短的写作并且仍然可以理解。另一种直接的方法是这样的

int bitCountLinear(long int n) {
    int len = sizeof(long int)*8;
    for (int i = 0; i < len; ++i) 
        if ((1UL<<i) > (unsigned long int)n) 
            return i;
    return len; 
}

剩下的可能会有点极端,但我试一试,所以我会分享它。 我怀疑可能有更快的方法可以做到这一点。例如,使用二进制搜索(即使64位的长度非常小)。所以我给你一个快速尝试,并为它带来乐趣。

union long_ing_family {
    unsigned long int uli;
    long int li;
};

int bitCountLogN(long int num) {
    union long_ing_family lif;
    lif.li = num;
    unsigned long int n = lif.uli;
    int res;
    int len = sizeof(long int)*8-1;
    int max = len;
    int min = 0;

    if (n == 0) return 0;
    do {
        res = (min + max) / 2;
        if (n < 1UL<<res)
            max = res - 1;
        else if (n >= (1UL<<(res+1)))
            min = res + 1;
        else
            return res+1;
    } while (min < max);

    return min+1;   // or max+1
}

然后我两个时间来看他们是否有任何有趣的差异......

#include <stdio.h>

#define REPS 10000000

int bitCountLinear(long int n);
int bitCountLogN(long int num);
unsigned long int timestamp_start(void);
unsigned long int timestamp_stop(void);
union long_ing_family;

int main(void) {

    long int n;
    long int begin, end;
    long int begin_Lin, end_Lin;
    long int begin_Log, end_Log;

    begin_Lin = 0;
    end_Lin = 0;
    begin_Log = 0;
    end_Log = 0;

    for (int i = 0; i < REPS; ++i) {
        begin_Lin += timestamp_start();
        bitCountLinear(i);
        end_Lin += timestamp_stop();
    }
    printf("Linear: %lu\n", (end_Lin-begin_Lin)/REPS);

    for (int i = 0; i < REPS; ++i) {
        begin_Log += timestamp_start();
        bitCountLogN(i);
        end_Log += timestamp_stop();
    }
    printf("Log(n): %lu\n", (end_Log-begin_Log)/REPS);

}

unsigned long int timestamp_start(void) {
    unsigned int cycles_low;
    unsigned int cycles_high;
    asm volatile ("CPUID\n\t"
        "RDTSCP\n\t"
        "mov %%edx, %0\n\t"
        "mov %%eax, %1\n\t": "=r" (cycles_high), "=r" (cycles_low)::"%rax", "%rbx", "%rcx", "%rdx");
    return ((unsigned long int)cycles_high << 32) | cycles_low;
}

unsigned long int timestamp_stop(void) {
    unsigned int cycles_low;
    unsigned int cycles_high;
    asm volatile ("RDTSCP\n\t"
        "mov %%edx, %0\n\t"
        "mov %%eax, %1\n\t"
        "CPUID\n\t": "=r" (cycles_high), "=r" (cycles_low)::"%rax", "%rbx", "%rcx", "%rdx");
    return ((unsigned long int)cycles_high << 32) | cycles_low;
}

......并不奇怪他们没有。 在我的机器上,我会得到类似的数字 线性:228 记录(n):224 假设存在大量背景噪声,则认为不同。

编辑: 我意识到我只测试了线性方法的最快解决方案,因此将功能输入更改为

bitCountLinear(0xFFFFFFFFFFFFFFFF-i);

bitCountLogN(0xFFFFFFFFFFFFFFFF-i);

在我的机器上,我会得到类似的数字 线性:415 记录(n):269 这显然是Log(n)方法的胜利。我没想到会在这里看到差异。