int中使用的计数位数

如果您有二进制数10110,我怎么能让它返回5? 例如,一个数字告诉我们使用了多少位? 下面列出了一些类似的例子:

  • 101应该返回3
  • 000000011应该返回2
  • 11100应该返回5
  • 101010101应该返回9

如何在Java中获得最简单的方法? 我已经提出了以下方法,但我可以更快地完成:

public static int getBitLength(int value) { if (value == 0) { return 0; } int l = 1; if (value >>> 16 > 0) { value >>= 16; l += 16; } if (value >>> 8 > 0) { value >>= 8; l += 8; } if (value >>> 4 > 0) { value >>= 4; l += 4; } if (value >>> 2 > 0) { value >>= 2; l += 2; } if (value >>> 1 > 0) { value >>= 1; l += 1; } return l; } 

最简单的?

 32 - Integer.numberOfLeadingZeros(value) 

如果您正在寻找算法,Java API的实现者同意您的分而治之的位移方法:

 public static int numberOfLeadingZeros(int i) { if (i == 0) return 32; int n = 1; if (i >>> 16 == 0) { n += 16; i <<= 16; } if (i >>> 24 == 0) { n += 8; i <<= 8; } if (i >>> 28 == 0) { n += 4; i <<= 4; } if (i >>> 30 == 0) { n += 2; i <<= 2; } n -= i >>> 31; return n; } 

编辑 :提醒那些信任浮点计算准确性的人,运行以下测试工具:

 public static void main(String[] args) { for (int i = 0; i < 64; i++) { long x = 1L << i; check(x); check(x-1); } } static void check(long x) { int correct = 64 - Long.numberOfLeadingZeros(x); int floated = (int) (1 + Math.floor(Math.log(x) / Math.log(2))); if (floated != correct) { System.out.println(Long.toString(x, 16) + " " + correct + " " + floated); } } 

第一个检测到的偏差是:

 ffffffffffff 48 49 

不幸的是,没有Integer.bitLength()方法直接给你答案。

BigInteger一个类似的方法,所以你可以使用那个:

 BigInteger.valueOf(value).bitLength() 

构造BigInteger对象会降低效率,但这只会影响数百万次。

您想要计算数字的基数2对数 – 具体来说:

  1 +楼(log 2 (价值)) 

Java有一个使用base e的Math.log方法,所以你可以这样做:

 1 + Math.floor(Math.log(value) / Math.log(2)) 

要小心你的要求。 一种非常快速的技术是进行表查找:

 int bittable [] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... }; int numbits (int v) { return bittable [v]; } 

其中bittable包含每个int的条目。 当然,这会带来负面价值的复杂性。 更实际的方法是计算数字的位域中的位

 int bittable [16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; int numbits (int v) { int s = 0; while (v != 0) { s += bittable [v & 15]; v >>= 4; } return s; } 

您真的只想找到最高位的位置1.请参阅此页面 ,标题为“查找整数的整数对数基数2(也就是最高位集的位置)”。

从这里开始 ,只需按位和添加即可:

 int GetHighestBitPosition(int value) { if (value == 0) return 0; int position = 1; if ((value & 0xFFFF0000) == 0) position += 16; if ((value & 0xFF00FF00) == 0) position += 8; if ((value & 0xF0F0F0F0) == 0) position += 4; if ((value & 0xCCCCCCCC) == 0) position += 2; if ((value & 0xAAAAAAAA) == 0) position += 1; return position; } 

我认为该数字的四舍五入的log_2将为您提供所需的内容。

就像是:

 return (int)(Math.log(value) / Math.log(2)) + 1; 
 int CountBits(uint value) { for (byte i = 32; i > 0; i--) { var b = (uint)1 << (i - 1); if ((value & b) == b) return i; } return 0; } 

如果你正在寻找最快的(没有一个表,这当然更快),这可能是一个:

 public static int bitLength(int i) { int len = 0; while (i != 0) { len += (i & 1); i >>>= 1; } return len; } 

Integer.toBinaryString(值)。长度()

另一种解决方案是使用根据API的BitSetlength()

返回“逻辑大小”…最高设置位的索引…加1。

要使用BitSet您需要创建一个数组。 所以它并不像从纯int开始那么简单。 但是你从JDK盒中得到它 – 经过测试和支持。 它看起来像这样:

  public static int bitsCount(int i) { return BitSet.valueOf(new long[] { i }).length(); } 

应用于问题中的示例:

  bitsCount(0b101); // 3 bitsCount(0b000000011); // 2 bitsCount(0b11100); // 5 bitsCount(0b101010101); // 9 

在询问位时, BitSet在我看来是合适的数据结构。