快速求比某个数大的2的幂值

分析

比如

x = 1	   res=2
x = 6	   res=8
x = 31   res=32
x = 100  res=128

以100为例,它的二进制表示是

0110 0100

128的二进制是

1000 0000

不难看出以下结论

  1. 2的幂次方的二进制表示必然只有一个1,其他值都是0
  2. x大,且为2的幂的数,二进制表示必然是x本身或者将x的二进制最高位1前一个数设置为1,然后其他位归0

做法1

  1. 先将x - 1,防止x本身就是2的幂的情况
  2. 求出x的先导零个数y
  3. 然后将-1向右移动y位得到z
  4. 最后z+1即为结果

案例

以100为例,假如用16位int存储

  1. x-1=99, 二进制表示

    0000 0000 0110 0011
    
  2. 最高位1到二进制最高位之间有9个0

  3. -1的二进制表示是全1,向右移动9位,得到y

    0000 0000 0111 1111 = y
    
  4. y+1的结果就是

    0000 0000 1000 0000 = 128
    

这就是java HashMap的做法

代码

public static int numberOfLeadingZeros(int i) {
	// HD, Count leading 0's
	if (i <= 0)
		return i == 0 ? 32 : 0;
	int n = 31;
	if (i >= 1 << 16) { n -= 16; i >>>= 16; }
	if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
	if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
	if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
	return n - (i >>> 1);
}
  
public static void main(String[] args) {
	int x = 100;
	int y = numberOfLeadingZeros(x - 1);
	int z = -1 >>> y;
	int res = z + 1;
	System.out.println(Integer.toBinaryString(res));
}

做法2

代码

func ceilingPowerOfTwo(i uint64) uint64 {
	i--
	i |= i >> 1
	i |= i >> 2
	i |= i >> 4
	i |= i >> 8
	i |= i >> 16
	i |= i >> 32
	i++
	return i
}

讲解

利用最高位的1,把1复制到其后的每一位,然后+1,即为结果

以如下值为例

0000 1000 0000 0000

i |= i >> 1

0000 1100 0000 0000

i |= i >> 2

0000 1111 0000 0000

i |= i >> 4

0000 1111 1111 0000

。。。。。

为什么最高不是64位?

前面已经说过,这里的目的是把最高位的1复制到其后的每一位,而64是uint64的最高位,不可能是二号位,所以只从32开始

posted @ 2023-08-24 18:34  INnoVation-V2  阅读(103)  评论(0)    收藏  举报