Integer位操作技巧解析

来源:互联网 发布:汉字书写教学软件 编辑:程序博客网 时间:2024/06/13 05:45

整数二进制左边1最早出现的位置

    public static int highestOneBit(int i) {        // HD, Figure 3-1        i |= (i >>  1);        i |= (i >>  2);        i |= (i >>  4);        i |= (i >>  8);        i |= (i >> 16);        return i - (i >>> 1);    }

画个图简单说明一下算原理,下图以8为为例,做了左移1,2,4位之后的效果,最终的效果就是在最早出现1的位置后面都是1。
32位的int也是类似的,最终的效果就是从左边第一位是1开始后面都是1。
这里写图片描述

整数二进制右边1最早出现的位置

    public static int lowestOneBit(int i) {        // HD, Section 2-1        return i & -i;    }

负数以补码形式存在,一个负数的补码,就是对应整数的二进制再取反加一。i和-i总有一个是正数,假设是i吧,由于两个数相加是0,在二进制角度来看,假设i最右边出现1的位置是k,那么在相同位置上-i必定也是1,并且-i在k以后的位也是0,这2位相加是0,并且进位1,那么要是k-1位相加得到0,两个数字在k-1位上只能是一个1,另外一个是0,以此类推,可以得到从左边第一位开始直到k-1位都是不同的。两个数进行与运算,只会在k位保留1,其他位都变成0。

整数二进制左边开头有连续多少个0

    public static int numberOfLeadingZeros(int i) {        // HD, Figure 5-6        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;    }

以移动16位为例子,如果左移16位之后是0,那么前16位都是0,那么就只要判断后面16位就可以了。
如果不是0,那么只要判断前面16位就可以了,和前面的区别就是,它不需要移位。后面的移位操作,以此类推就可以了。

整数二进制右边结束有连续多少个0

    public static int numberOfTrailingZeros(int i) {        // HD, Figure 5-14        int y;        if (i == 0) return 32;        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);    }

和上面的差不多,假设右移16位不等于0,那么说明只需要判断右边16位就可以了。如果等于0,那说明要判断左边16位。后面的移位操作,以此类推就可以了。

整数二进制总共有多少个1

    public static int bitCount(int i) {        // HD, Figure 5-2        i = i - ((i >>> 1) & 0x55555555);        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);        i = (i + (i >>> 4)) & 0x0f0f0f0f;        i = i + (i >>> 8);        i = i + (i >>> 16);        return i & 0x3f;    }

这个算法也是神乎其技,它的做法是分别计算每2位,每4位,每8位,每16位,每32位..这样的顺序计算.以第一行为例,每2位有4种情况,分别是00,01,10,11, 计算i-((i>>>1) & 01) 可以得到00,01,01,10, 就表示1的个数。

整数向左滚动X位

    public static int rotateLeft(int i, int distance) {        return (i << distance) | (i >>> -distance);    }

这是基本的移位操作,注意的是右边要采用算术右移。

整数向右滚动X位

    public static int rotateRight(int i, int distance) {        return (i >>> distance) | (i << -distance);    }

和上面的一样,就不再详述了。

整数二进制反转

    public static int reverse(int i) {        // HD, Figure 7-1        i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;        i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;        i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;        i = (i << 24) | ((i & 0xff00) << 8) |            ((i >>> 8) & 0xff00) | (i >>> 24);        return i;    }

以第一行为例,它的作用就是两两交换,可以通过下图分析可得。
这里写图片描述
同理,第二行是每2位交换,第三行是每4位交换,假设原来是b1b2b3b4b5b6b7b8,那么三行执行后,结果就是b8b7b6b5b4b3b2b1,就是一个字节的位进行反转了。最后一句就是按字节反转一下,最终结果就是按位反转了。

整数的符号,0返回0,正数返回1,负数返回-1

    public static int signum(int i) {        // HD, Section 2-7        return (i >> 31) | (-i >>> 31);    }

感觉这个实现有点多此一举,直接大小判断很简单,也很直观,为什么不采用?

还是画个图说明一下吧。
这里写图片描述

整数按字节反转

    public static int reverseBytes(int i) {        return ((i >>> 24)           ) |               ((i >>   8) &   0xFF00) |               ((i <<   8) & 0xFF0000) |               ((i << 24));    }

这个算法很好理解,第一个字节右移24位就跑到第四个字节去了,第二个字节右移8位到了第三位,和FF00与运算就抹掉对第四个字节的影响。后面的就不解释了。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 立定跳不会收腹怎么办 1岁宝宝有蛔虫怎么办 手机屏幕总是有网页跳出来怎么办 cs游戏屏幕变成正方形怎么办 大王卡被收回了怎么办 模拟人生4小人生病了怎么办 创造与魔法死后怎么办? 脚不小心扭伤了该怎么办 小鸡脚扭伤了该怎么办 跳高比赛最终成绩相等怎么办 热车1200怠速降不下来怎么办 大腿根骨髓水肿越来越疼怎么办 倒库方向打晚了怎么办 签吻芳颜祛斑液脸脱皮怎么办 3d右边工具栏消失了怎么办 3d菜单栏消失了怎么办 觉得自己性无能不敢谈对象怎么办 护士面试时被问到病人坠床怎么办 三次元仪器坏了怎么办 运动同手同脚怎么办 狗狗突然害怕不敢走路怎么办 一岁半宝宝因为害怕不敢走路怎么办 猫把背拱起来怎么办 穿猫跟鞋走路不稳怎么办 狗狗后腿内八字怎么办 快走后小腿粗了怎么办? 猫的嘴巴烂了怎么办 苹果8丢了已关机怎么办 肚子吃多了难受怎么办 喝水喝的肚子胀怎么办 肚子吃撑了难受怎么办 肚子撑得想吐怎么办 吃饭吃的太饱怎么办 吃饭吃的太撑怎么办 跑步迈不开步子怎么办 踏步走步子反了怎么办 微信不支持计步怎么办 肝癌二次介入后头晕心慌怎么办 跑步跑得胃疼怎么办 如果世界上的猪都死了怎么办 我和我老婆吵架怎么办