前言
php的位运算很少会用到,但是用处很大,
在有些算法中会用到,在权限管理中也会经常用到,
对于理解计算机的世界也会有一定的帮助,所以得把这些重要但不常用的东西总结一下记录一下。
提到位运算,避不开的是二进制。
因为位运算是直接在内存做操作和运算,相较与直接拿两个变量做运算符肯定是更快的。
很多地方把二进制这玩意说得很晦涩,现在来以最简单的方式来总结一下,当然只算 int 范围内的数算了,超过了这个范畴程序员还不如拿这时间去学点别的。
基本点
- 电脑运算是以二进制方式来进行计算的,且为补码,任何运算都是以补码方式进行运算得出结果再转为原码转为十进制数字的,无论什么编程语言都是这样的。
- 一个正数的,原码,反码,补码都一样。
- 第一个高位为符号位,0代表正数,1代表负数
- 原码往反码推是符号位不变,其他的0变1,1变0,反码往补码推是反码加1,反之补码往反码推那就是减一了。
- php不支持无符号数
- 0的正反补都是4*8个0
二进制解释
说完以上总结,再来解释下什么是二进制,网上大把,
但只要记住,int范围内的数也就是我们大部分需要用到的数,都可以用二进制来表示。
我们生活中用到的计数方式为十进制,由个数位满10进1,
然后再开始重新计算,等十位满9再加一时,百位加一,十位归零。
二进制则只有两个数字来表示就是0和1,满2进1。
由32个位组成,虽然只有32个位但已满足了我们正常的需求了
示例:
比如说1转换为2进制原码,由于1是正数所以符号位为0,
原码反码补码都一个样。
1的原码:00000000 00000000 00000000 00000001
因手懒,太多0太丑用+拼接,'0* 8'代表8个0
2的原码:0* 8 0* 8 0* 8 0* 6 + 1 0,既然是二进制,
满2就得进1,最低位归0,向前加一。
再来解释下负数的原码反码和补码,就开始讲php的位运算了。
先来讲-1,刚开始说了,最高位为符号位,既然是负数那自然符号位为1.
-1的原码: 1+0*7 0*8 0*8 0*7+1;
-1的反码: 1*8 1*8 1*8 1*7+0;符号位不变,其他的0和1互换
-1的补码:1*8 1*8 1*8 1*8;反码加一则为补码。
二进制复习完毕。下面开始讲讲php的位运算。
位运算
php一共有六种位运算,一种一种来讲。
1. 按位与,‘&’:
可以这么理解,两个数的补码放在一起比较每个位(一共32个位),
可以得出另外一个数,这个数字的组成由比较的两位数字生成,
如果两个数的每个位数上的数字都等于1的话,
那得到的那个数的补码的同位为1,否则为0。
听着绕口,其实很简单,觉得还是比官网上的更容易让新手看懂
下面举例子:
$a = -1&7;问$a等于多少?
首先来求-1和7的补码。7的原码就是补码。
7: 0* 8 0* 8 0* 8 0* 5 + 1 1 1。这就是7的补码
-1: 1+0*7 0*8 0*8 0*7+1。这是-1的原码
-1: 1*8 1*8 1*8 1*7+0。这是-1的反码
-1: 32*1;全都是1是-1的补码。
两个补码都有了下面开始运算:
-1:11111111 11111111 11111111 11111111
7 :00000000 00000000 00000000 00000111
按照上面的说法,每个位都有一样则 $a
的同等位则为1,刚好-1的补码和7的补码前面都不一样,就最后三位一样,所以刚好求得的 $a
的补码的最后三位是1而其他的都是0,刚好这个补码为正数,正好就是7。
2. 按位或,'|':
其实就是和按位与相反,只要有1个为1,那就为1,如果都不为1,那就为0。
$a = -1|7
;得出来的 $a
补码为32个1,但此时不能说 $a
就是-1,因为这只是补码,要转成原码再转成十进制数,补码-1,然后再翻转,再转出来,得到的其实也还是-1。
3. 按位取反,'~':
就是将这个数的补码全部翻转过来,包括符号位,0变1,1变0
取反的结果一定是整数变负数负数变正数,取正数的反时,
记得一定要从补码一步步转到原码再转成十进制数才是答案。
4. 按位异或,'^':
两个数的补码比较,同等位上的两数比较
,不一样时,则答案的补码的同位则为1,否则为0。
5. 算数左移和右移
往左移符号位被挤走右边0补充,往右移动,符号位不动,
高位以符号位补充。二进制世界里往左移动其实是相当于乘以了2,
右移相当于除以了2。
不吹牛逼的说,这应该是互联网上最容易理解的php位运算的解释和二进制的解释了。
原文链接:php的位运算总结-PHP
网友评论