程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

JDK源码之Integer类——numberOfLeadingZeros()方法

发布于2021-05-29 20:00     阅读(632)     评论(0)     点赞(29)     收藏(4)


方法功能:获取指定整数转换成二进制后的前导零的个数。

比如数字3的二进制是0000 0000 0000 0000 0000 0000 0000 0011,那么可以得到它的前置0有30位,最后两位是11。

该方法的源码如下:

  1. /**
  2. * Returns the number of zero bits preceding the highest-order
  3. * ("leftmost") one-bit in the two's complement binary representation
  4. * of the specified {@code int} value. Returns 32 if the
  5. * specified value has no one-bits in its two's complement representation,
  6. * in other words if it is equal to zero.
  7. *
  8. * <p>Note that this method is closely related to the logarithm base 2.
  9. * For all positive {@code int} values x:
  10. * <ul>
  11. * <li>floor(log<sub>2</sub>(x)) = {@code 31 - numberOfLeadingZeros(x)}
  12. * <li>ceil(log<sub>2</sub>(x)) = {@code 32 - numberOfLeadingZeros(x - 1)}
  13. * </ul>
  14. *
  15. * @param i the value whose number of leading zeros is to be computed
  16. * @return the number of zero bits preceding the highest-order
  17. * ("leftmost") one-bit in the two's complement binary representation
  18. * of the specified {@code int} value, or 32 if the value
  19. * is equal to zero.
  20. * @since 1.5
  21. */
  22. public static int numberOfLeadingZeros(int i) {
  23. // HD, Figure 5-6
  24. if (i == 0)
  25. return 32;
  26. int n = 1;
  27. if (i >>> 16 == 0) { n += 16; i <<= 16; }
  28. if (i >>> 24 == 0) { n += 8; i <<= 8; }
  29. if (i >>> 28 == 0) { n += 4; i <<= 4; }
  30. if (i >>> 30 == 0) { n += 2; i <<= 2; }
  31. n -= i >>> 31;
  32. return n;
  33. }

对该方法进行注释:

  1. /**
  2. * 回指定int值的二进制补码二进制表示形式中最高位(“最左端”)一位之前的零位数目。 如果指定值的二进制补码表示中没有一位(即等于零),则返回32。
  3. * 注意,此方法是密切相关的数底2对所有正int值x:
  4. * floor(log 2 (x))= 31 - numberOfLeadingZeros(x)
  5. * ceil(log 2 (x))= 32 - numberOfLeadingZeros(x - 1)
  6. * 比如数字3的二进制是0000 0000 0000 0000 0000 0000 0000 0011,那么可以得到它的前置0有30位,最后两位是11
  7. * 比如数字8的二进制是0000 0000 0000 0000 0000 0000 0000 1000,那么可以得到它的前置0有28位,最后四位是1000
  8. * 参考链接:https://blog.csdn.net/cnds123321/article/details/117338989
  9. *
  10. * @param i 要计算前导零个数的值
  11. * @return 指定的int值的二进制补码二进制表示形式中("最左端")一位之前的零位数目;如果该值等于0,则为32位
  12. */
  13. public static int numberOfLeadingZeros(int i) {
  14. // 如果传入的数是0,那么32位二进制一定都是0,所以直接返回32即可,不需要再进行下面的操作
  15. if (i == 0)
  16. return 32;
  17. // 局部变量,统计前导零的个数,初始值为1,即至少存在1个,因为0个情况已经被上面的if判断排除了
  18. int n = 1;
  19. // 这个思路就是二分查找,首先把32位的数分为高低16位,如果非零值位于高16位,后续再将高16位继续二分为高低8位,一直二分到集合中只有1个元素
  20. /*
  21. 将i无符号右移16位后,有二种情况:
  22. 第一种情况,i=0,则第一个非零值位于低16位,i至少有16个前导0,同时将i左移16位(把低16位移到原高16位的位置,这样情况1和情况2就能统一后续的判断方式)
  23. 例如:数字123的二进制是0000 0000 0000 0000 0000 0000 0111 1011,无符号右移16位后二进制是0000 0000 0000 0000 0000 0000 0000 0000,表明第一个非零值在低16位
  24. 第二种情况,i!=0,则第一个非零值位于高16位,后续在高16位中继续判断
  25. */
  26. // 只是判断当i无符号右移16位后是否等于0,如果等于0则表示第一个非零值在低16位,如果不等于则表示第一个非零值在高16位
  27. if (i >>> 16 == 0) {
  28. // 执行到这里,表示第一个非零值在低16位,那么表示数字i的高16位全是0,也就是说至少有16个前导0,用n记录起来
  29. n += 16;
  30. // 既然i的第一个非零值在低16位,那么将i左移16位,将低16位移动到原来高16位的位置,继续判断
  31. // 例如:数字123的二进制是0000 0000 0000 0000 0000 0000 0111 1011,左移16位后二进制是0000 0000 0111 1011 0000 0000 0000 0000
  32. i <<= 16;
  33. }
  34. // 判断第一个非零值是否在高8位,如果i>>>24==0为true表示第一个非零值在低8位,为false表示在高8位
  35. if (i >>> 24 == 0) {
  36. // 执行到这里,表示第一个非零值在低8位,那么表示数字i的高8位全是0,也就是说至少有8个前导0,用n记录起来
  37. n += 8;
  38. // 既然i的第一个非零值在低8位,那么将i左移8位,将低8位移动到原来高8位的位置,继续判断
  39. // 例如:数字123的二进制是0000 0000 0000 0000 0000 0000 0111 1011
  40. // 左移16位后二进制是 0000 0000 0111 1011 0000 0000 0000 0000
  41. // 又左移8位后二进制是 0111 1011 0000 0000 0000 0000 0000 0000
  42. i <<= 8;
  43. }
  44. // 判断第一个非零值是否在高4位,如果i>>>28==0为true表示第一个非零值在低4位,为false表示在高4位
  45. if (i >>> 28 == 0) {
  46. // 执行到这里,表示第一个非零值在低4位,那么表示数字i的高4位全是0,也就是说至少有4个前导0,用n记录起来
  47. n += 4;
  48. // 既然i的第一个非零值在低4位,那么将i左移4位,将低4位移动到原来高4位的位置,继续判断
  49. // 例如:数字1的二进制是0000 0000 0000 0000 0000 0000 0000 0001
  50. // 左移16位后二进制是 0000 0000 0000 0001 0000 0000 0000 0000
  51. // 又左移8位后二进制是 0000 0001 0000 0000 0000 0000 0000 0000
  52. // 又左移4位后二进制是 0001 0000 0000 0000 0000 0000 0000 0000
  53. i <<= 4;
  54. }
  55. // 判断第一个非零值是否在高2位,如果i>>>30==0为true表示第一个非零值在低2位,为false表示在高2位
  56. if (i >>> 30 == 0) {
  57. // 执行到这里,表示第一个非零值在低2位,那么表示数字i的高2位全是0,也就是说至少有2个前导0,用n记录起来
  58. n += 2;
  59. // 既然i的第一个非零值在低2位,那么将i左移2位,将低2位移动到原来高2位的位置,继续判断
  60. // 例如:数字1的二进制是0000 0000 0000 0000 0000 0000 0000 0001
  61. // 左移16位后二进制是 0000 0000 0000 0001 0000 0000 0000 0000
  62. // 又左移8位后二进制是 0000 0001 0000 0000 0000 0000 0000 0000
  63. // 又左移4位后二进制是 0001 0000 0000 0000 0000 0000 0000 0000
  64. // 又左移2位后二进制是 0100 0000 0000 0000 0000 0000 0000 0000
  65. i <<= 2;
  66. }
  67. // i >>> 31是判断第一个非零值是否在高1位,如果在高1位则i>>>31得到的结果是1,如果在低1位则i>>>31得到的结果是0
  68. // n由于是从1开始的,所以这里需要减,如果是从0开始,就需要加
  69. n -= i >>> 31;
  70. // 返回统计的前导零个数
  71. return n;
  72. }

其实这个方法就是利用位运算求前导零的个数,思路就是不断进行二分来记录统计前导零的出现次数

画了一个图,可能方便理解些:

原文链接:https://blog.csdn.net/cnds123321/article/details/117338989



所属网站分类: 技术文章 > 博客

作者:我是个大美女

链接:http://www.javaheidong.com/blog/article/207103/79a6039991c80dcca881/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

29 0
收藏该文
已收藏

评论内容:(最多支持255个字符)