java按位运算,和移位运算

我们都知道,在计算机内部,数据都是已二进制的形式存在的,而对于负数来说,是以补码的形式存在,而按位运算和移位运算都是建立在二进制的基础上的,之前看见了java的一个api,是将一个数的2进制展示的出来的功能一个函数,就是Integer类中的toBinaryString()方法。本方法是展示2进制,同时还有另外两个方法,分别为toHexString(int i)和方法toOctalString(int i),分别对应16进制输出和8进制输出,对于这三个方法我们研究了源码发现,他们都有调用toUnsignedString0(int val, int shift)这个方法,只不过shift不同而已,分别为1 3 4 。
对于toUnsignedString0方法而言,内部调用了2个方法,第一个方法是Integer.numberOfLeadingZeros(int val),这个方法的作用就是计算出用于表示二/八/十六进制的字符数组的长度,第二个就是使用formatUnsignedInt方法填充字符数组,得到所需进制表示的字符串并返回。
对于第一个方法,我们假设计算机32位,那么对于比如对于5来说,它的字符串应该该是101,那么其他的高位应该就是0,换句话说输出的时候应该把高位多余的0去掉(000000…00101),那就是要计算前面都有几个0,我能想到的方法就是移位然后一位一位的判断,那么可以与1000 0000 0000 0000 0000 0000 0000 0000进行与运算,因为数据在机器中存的是2进制(对于负数来说是补码),所以可以这样写代码
public static int numberOfLeadingZeros0(int i){
if(i == 0)
return 32;//数字为0的话就是32位
int n = 0;
int o= 0x80000000;
int j = i & o;//相与判断
while(j == 0){//一旦出现1,就停止,返回n
n++;
i <<= 1;//每移位一次就判断一次
j = i & mask;
}
return n;
}
这样的方法的时间复杂度是n,而源代码是
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; },如果高8位为0,那么就把这个高8位移走,低位补上继续运算
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}这个算法就是分治算法**为啥是2的倍数,因为这样到最后要么就是剩一个0 ,要么就直接删减到1的位置了**
这个算法实在是太巧了,巧用移位,不断在缩小范围,最后一步n-=i>>>31,就是还剩两位的时候(类似于前面的01000000...0000,让他右移31,判断最高位是不是0,是0说明是n=1,不是0说明,n=30,最后判断要么就是10或者01,

接下来n获取后就要开始获取二进制的值了
类似的代码如下
{private static String toUnsignedString(int i, int shift,int n) {
50
52 int radix = 1 << shift;//将1扩大至2的shift次方倍
53 int mask = radix - 1;
54 do {
55
57
58 buf[–n] = digits[i & mask];//类似于取余数,对于二进制可以用与1相与的方法判断某个数是不是奇数或者偶数
59 i >>>= shift;//右移赋值,类似于不断除以进制数
60
63 } while (i != 0);
64 return new String(buf);
65 }
}

原文参考:https://blog.csdn.net/u013190513/article/details/70216730
本人技术小白,可能写的东西就是随笔一记,如果看不懂或者有问题欢迎大家批评和提出,下次会努力改正

你可能感兴趣的:(java按位运算,和移位运算)