如何计算一个数字在二进制中将具有的1个数?

2022-09-01 02:16:56

可能的重复:
在32位整数中计算设置位数的最佳算法?

如何计算一个数字在二进制中的数量?1

所以假设我有一个数字,它等于二进制,并且有4个。编写算法来执行此操作的最有效方法是什么?451011011


答案 1

与其编写算法来执行此操作,不如最好使用内置函数。Integer.bitCount()

使这特别有效的是JVM可以将其视为固有的。即,在支持它的平台上识别并用单个机器代码指令替换整个事物,例如英特尔/ AMD


展示这种优化的有效性

public static void main(String... args) {
    perfTestIntrinsic();

    perfTestACopy();
}

private static void perfTestIntrinsic() {
    long start = System.nanoTime();
    long countBits = 0;
    for (int i = 0; i < Integer.MAX_VALUE; i++)
        countBits += Integer.bitCount(i);
    long time = System.nanoTime() - start;
    System.out.printf("Intrinsic: Each bit count took %.1f ns, countBits=%d%n", (double) time / Integer.MAX_VALUE, countBits);
}

private static void perfTestACopy() {
    long start2 = System.nanoTime();
    long countBits2 = 0;
    for (int i = 0; i < Integer.MAX_VALUE; i++)
        countBits2 += myBitCount(i);
    long time2 = System.nanoTime() - start2;
    System.out.printf("Copy of same code: Each bit count took %.1f ns, countBits=%d%n", (double) time2 / Integer.MAX_VALUE, countBits2);
}

// Copied from Integer.bitCount()
public static int myBitCount(int i) {
    // HD, Figure 5-2
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}

指纹

Intrinsic: Each bit count took 0.4 ns, countBits=33285996513
Copy of same code: Each bit count took 2.4 ns, countBits=33285996513

使用固有版本和循环的每个位计数平均只需0.4纳秒。使用相同代码的副本需要6倍的时间(获得相同的结果)


答案 2

在我所知道的32位变量中计算1个数量的最有效方法是:v

v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // c is the result

更新:我想明确一点,这不是我的代码,实际上它比我更老。根据Donald KnuthThe Art of Computer Programming Vol IV,第11页)的说法,该代码首次出现在威尔克斯,惠勒和吉尔的第一本编程教科书《电子数字计算机程序的准备》(1957年第2版,1984年重印)中。该书第2版的第191-193页介绍了D B Gillies和J C P Miller的Nifty Parallel Count


推荐