Integer.numberOfLeadingZeros()源码原理

一筐愿望 2015-05-25 04:13:14
	
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;
}

该函数可以返回二进制首部开始0的个数
如:2818048,对应二进制:00000000 00101011 00000000 00000000,会返回10

但是这个函数的原理是什么呢?而且为什么基准选定的分别是2的1、2、3、4次幂呢?
...全文
619 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
一筐愿望 2015-06-04
  • 打赏
  • 举报
回复
引用 4 楼 whyshr 的回复:
[quote=引用 2 楼 u011605971 的回复:] [quote=引用 1 楼 skgary 的回复:] 这里典型的二分查找思路。 if (i >>> 16 == 0) { n += 16; i <<= 16; } 先看左边的16位,如果有,记16个,如果没有,把右16位移到左边。 然后依次是8位,4位,2位,1位,依次类推。
大哥您好,问个挺弱的问题,,,这里为什么就能选中16、8、4、2、1,怎么就不选9、7、5、3、1呢......,是根据什么思路二分查找的...或者我该去补一下什么叫二分查找?[/quote] 首先,查找从首部开始0的个数,可以理解成查找从首部开始第一个1的位置。针对这个问题numberOfLeadingZeros方法用了二分查找法。至于为什么二分查找的中值要选16->8->4->2->1,个人认为这样取值的的平均比较次数最少,不管要找的元素位于哪个位置,每次比较都能淘汰集合中一半的元素,从而能够快速定位。[/quote] 前辈您好,感谢您回答我的问题 我所接触到的二分查找都是基于一个有序的数组之类的,这里怎么也能看作是二分查找呢?难道将32除以2,再除以2,再除以2这样找下去就算是一种二分查找吗 这个方法看了这么久我都背下来了...但是还是不明白其中的所以然,因为不知道为什么会这么实现,求前辈再指点我一下下,感激不尽
  • 打赏
  • 举报
回复
看看这样解释是否清楚一些:

	// 首先在jvm中一个int类型的数据占4个字节,共32位,其实就相当于一个长度为32的数组。
	// 那我们要计算首部0的个数,就是从左边第一个位开始累加0的个数,直到遇到一个非零值。
	public static int numberOfLeadingZeros(int i) {
		if (i == 0)                                                                       
            	return 32;
		int n = 1;
		// 下面的代码就是定位从左边开始第一个非零值的位置,在定位过程中顺便累加从左边开始0的个数
		// 将i无符号右移16位后,有二种情况;
		//   情况1.i=0,则第一个非零值位于低16位,i至少有16个0,同时将i左移16位(把低16位移到原高16位的位置,这样情况1和情况2就能统一后续的判断方式)
		//   情况2.i!=0,则第一个非零值位于高16位,后续在高16位中继续判断
		// 这个思路就是二分查找,首先把32位的数分为高低16位,如果非零值位于高16位,后续再将高16位继续二分为高低8位,一直二分到集合中只有1个元素
		if (i >>> 16 == 0) { n += 16; i <<= 16; }
		// 判断第一个非零值是否位于高8位
		if (i >>> 24 == 0) { n +=  8; i <<=  8; }  
		// 判断第一个非零值是否位于高4位
		if (i >>> 28 == 0) { n +=  4; i <<=  4; }
		// 判断第一个非零值是否位于高2位
		if (i >>> 30 == 0) { n +=  2; i <<=  2; }       
		// 判断第一个非零值是否位于左边第一位
		n -= i >>> 31;                                                                
		return n;
	}
  • 打赏
  • 举报
回复
引用 2 楼 u011605971 的回复:
[quote=引用 1 楼 skgary 的回复:] 这里典型的二分查找思路。 if (i >>> 16 == 0) { n += 16; i <<= 16; } 先看左边的16位,如果有,记16个,如果没有,把右16位移到左边。 然后依次是8位,4位,2位,1位,依次类推。
大哥您好,问个挺弱的问题,,,这里为什么就能选中16、8、4、2、1,怎么就不选9、7、5、3、1呢......,是根据什么思路二分查找的...或者我该去补一下什么叫二分查找?[/quote] 首先,查找从首部开始0的个数,可以理解成查找从首部开始第一个1的位置。针对这个问题numberOfLeadingZeros方法用了二分查找法。至于为什么二分查找的中值要选16->8->4->2->1,个人认为这样取值的的平均比较次数最少,不管要找的元素位于哪个位置,每次比较都能淘汰集合中一半的元素,从而能够快速定位。
skgary 2015-06-02
  • 打赏
  • 举报
回复
引用 2 楼 u011605971 的回复:
[quote=引用 1 楼 skgary 的回复:] 这里典型的二分查找思路。 if (i >>> 16 == 0) { n += 16; i <<= 16; } 先看左边的16位,如果有,记16个,如果没有,把右16位移到左边。 然后依次是8位,4位,2位,1位,依次类推。
大哥您好,问个挺弱的问题,,,这里为什么就能选中16、8、4、2、1,怎么就不选9、7、5、3、1呢......,是根据什么思路二分查找的...或者我该去补一下什么叫二分查找?[/quote] 这。。。问题问的就像为何INT在32位系统上用四个byte一样。。。。 我实在无法回答 。。。
一筐愿望 2015-06-02
  • 打赏
  • 举报
回复
引用 1 楼 skgary 的回复:
这里典型的二分查找思路。 if (i >>> 16 == 0) { n += 16; i <<= 16; } 先看左边的16位,如果有,记16个,如果没有,把右16位移到左边。 然后依次是8位,4位,2位,1位,依次类推。
大哥您好,问个挺弱的问题,,,这里为什么就能选中16、8、4、2、1,怎么就不选9、7、5、3、1呢......,是根据什么思路二分查找的...或者我该去补一下什么叫二分查找?
skgary 2015-05-26
  • 打赏
  • 举报
回复
这里典型的二分查找思路。 if (i >>> 16 == 0) { n += 16; i <<= 16; } 先看左边的16位,如果有,记16个,如果没有,把右16位移到左边。 然后依次是8位,4位,2位,1位,依次类推。

62,624

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧