numberOfTrailingZeros(long i)方法的作用
该方法的作用是传入一个long值,转换为二进制,计算从低位开始总共有多少个连续的0.与之对应的还有一个方法:
numberOfLeadingZeros(long i),该方法是求对于给定的long值,转换为二进制后,从高位开始有多少个连续的0.
numberOfTrailingZeros(long i)方法的思路
long类型总0的数量最多64个.二分法,每次看低位的一半是否含有1,如果含有1,那么高位的一半不用看了,只看低位的这一半就行了.如果低位的一半没有1,那么只看高位的那一半.
源码
public static int numberOfTrailingZeros(long i) {
// HD, Figure 5-14
int x, y;
if (i == 0) return 64;
int n = 63;
y = (int)i; if (y != 0) { n = n -32; x = y; } else x = (int)(i>>>32);
y = x <<16; if (y != 0) { n = n -16; x = y; }
y = x << 8; if (y != 0) { n = n - 8; x = y; }
y = x << 4; if (y != 0) { n = n - 4; x = y; }
y = x << 2; if (y != 0) { n = n - 2; x = y; }
return n - ((x << 1) >>> 31);
}
源码解析
为了方便阅读,已将简约的代码格式化为多行.
//x用来接收切割后值不为0的一半
//y用来接收切割后剩下的低位的一半
int x, y;
//例i = 0100 1010 0011 1010 0100 0000 0011 0111 1111 0011 1111 0000 0000 0000 0000 0000
if (i == 0) {
//全是0
return 64;
}
//上面全是0的情况已经被排除了.下面的分割中,如果y不等于0,则x=y;如果y==0,则x等于另一半,反正x不可能全是0
//n代表连续的0的个数
int n = 63;
y = (int)i;//long转换为整数后,取的是i的低32位的值,高位的被抹去.
//例:y = 1111 0011 1111 0000 0000 0000 0000 0000
if (y != 0) { //说明i低32位有1,看后32位即可
n = n -32; //不用看前32位,减去32 //例: n=31
x = y; //给x赋值,=i的后32位 //例: x = 1111 0011 1111 0000 0000 0000 0000 0000
}else { //后32位没有1,再看前32位
x = (int)(i>>>32); //给x赋值,高位的32位覆盖低位的32位,x=i的前32位的值
}
y = x <<16; //x左移16位,保留x的低16位的值.高位的值自动被抹去.低位补0.
//例: y = 0000 0000 0000 0000 0000 0000 0000 0000 ,y==0,不进入下面判断
if (y != 0) { //说明x低16位有1
n = n -16;//不用看前16位,减去16
x = y;//给x赋值,等于原x的低16位
}
y = x << 8; //x左移8位,保留x的低8位,放到到int最高的8位.低位补0.
//例: y = 1111 0000 0000 0000 0000 0000 0000 0000
if (y != 0) { //说明x低8位有1
n = n - 8; //不用看前8位,减去8 //例: n= 23
x = y;//将低8位赋值给x //x=1111 0000 0000 0000 0000 0000 0000 0000
}
y = x << 4; //例: y=0000 0000 0000 0000 0000 0000 0000 0000
if (y != 0) {
n = n - 4;
x = y;
}
y = x << 2; //x左移2位,保留x的低2位的值,放到到int最高的2位 //例: y=1100 0000 0000 0000 0000 0000 0000 0000
if (y != 0) {//说明x低2位有1
n = n - 2;//不用看前2位,减去2 //例:n=21
x = y;//将低2位赋值给x //例: x= 1100 0000 0000 0000 0000 0000 0000 0000
}
//x不可能全是0,所以x为0100...,1000...,1100...,不可能是0000...
// 因为最开始已经减去了1个0,所以如果第二位是1,那么还要减去1个0,如果第二位不是1,那么高位一定是1,不用减0
//x左移一位,再右移31位,则只保留x的第2位的数
//如果第2位的数是1,那么减去这1位.如果第2位的数是0,不用减
return n - ((x << 1) >>> 31);
//例: (x << 1) >>> 31 结果为1,n=20