publicstaticintnumberOfLeadingZeros(int i){ // HD, Figure 5-6 if (i == 0) return32; 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; }
publicstaticintnumberOfTrailingZeros(int i){ // HD, Figure 5-14 int y; if (i == 0) return32; int n = 31; y = i <<16; if (y != 0) { n = n -16; i = y; } y = i << 8; if (y != 0) { n = n - 8; i = y; } y = i << 4; if (y != 0) { n = n - 4; i = y; } y = i << 2; if (y != 0) { n = n - 2; i = y; } return n - ((i << 1) >>> 31); }
publicstaticintnumberOfLeadingZeros(int i){ if (i == 0) return32; int n = 1; // 如果从左往右第一个1出现在低16位,那么结果加16,然后把低16位移到高16位 // 如: 0000 0000 0000 0000 0000 0000 0000 0010 // 变为:0000 0000 0000 0010 0000 0000 0000 0000 if (i >>> 16 == 0) { n += 16; i <<= 16; } // 如果从左往右第一个1出现在低8位,那么结果加8,然后把低8位移到高8位 // 变为:0000 0010 0000 0000 0000 0000 0000 0000 if (i >>> 24 == 0) { n += 8; i <<= 8; } // 如果从左往右第一个1出现在低4位,那么结果加4,然后把低4位移到高4位 // 变为:0010 0000 0000 0000 0000 0000 0000 0000 if (i >>> 28 == 0) { n += 4; i <<= 4; } // 如果从左往右第一个1出现在低2位,那么结果加2,然后把低2位移到高2位 // 变为:10 0000 0000 0000 0000 0000 0000 0000 00 if (i >>> 30 == 0) { n += 2; i <<= 2; } // 如果如果从左往右第一个1出现在倒数第2低位,那么结果需要减1,因为n的初始值为1 n -= i >>> 31; return n; }
上面 n 的初始值做了特殊处理,纯粹的二分可以写成如下:
1 2 3 4 5 6 7 8 9 10 11
publicstaticintnumberOfLeadingZeros2(int i){ if (i == 0) return32; int n = 0; 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; } if (i >>> 31 == 0) { n += 1; } return n; }
publicstaticintnumberOfTrailingZeros(int i){ int y; if (i == 0) return32; int n = 31; // 如果从右往左第一个1出现在低16位,那么结果减16,然后把低16位移到高16位 y = i <<16; if (y != 0) { n = n -16; i = y; } // 如果从右往左第一个1出现在低8位,那么结果减8,然后把低8位移到高8位 y = i << 8; if (y != 0) { n = n - 8; i = y; } // 如果从右往左第一个1出现在低4位,那么结果减4,然后把低4位移到高4位 y = i << 4; if (y != 0) { n = n - 4; i = y; } // 如果从右往左第一个1出现在低2位,那么结果减2,然后把低2位移到高2位 y = i << 2; if (y != 0) { n = n - 2; i = y; } return n - ((i << 1) >>> 31); }
上面 n 的初始也可以设为0,然后后面采用加法,只不过这样每次判断要进行两次位移,相比上面每次判断只进行一次位移比较高效。
1 2 3 4 5 6 7 8 9 10 11
publicstaticintnumberOfTrailingZeros2(int i){ if (i == 0) return32; int n = 0; // 如果从右往左第一个1出现在高16位,那么结果加16,然后把高16位移到低16位 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; } if (i << 31 == 0) { n += 1; i >>>= 1; } return n; }
publicstaticintnumberOfLeadingZeros3(int i){ int y; if (i == 0) return32; int n = 31; // 如果从左往右第一个1出现在高16位,那么结果减16,然后把高16位移到低16位 y = i >>>16; if (y != 0) { n = n -16; i = y; } y = i >>> 8; if (y != 0) { n = n - 8; i = y; } y = i >>> 4; if (y != 0) { n = n - 4; i = y; } y = i >>> 2; if (y != 0) { n = n - 2; i = y; } return n - (i >>> 1); }
也许,numberOfTrailingZeros 和 numberOfLeadingZeros 实现思路是判断第一位1(不管是最左边还是最右边)是否在低 x 位吧,然后不断把这低 x 位移到高 x 位进行判断(x=16, 8, 4, 2)。