移位包括有符号左移(<<)、有符号右移(>>)、无符号右移(>>>),其中 js 支持三种移位,PHP只支持前两种移位(没查到第三种),恰好需要PHP进行无符号右移,此处实现一下。先看结果
将数字 $a 向右无符号移动 $n 位
[php] view plain copy
function uright($a, $n)
{
$c = 2147483647>>($n-1)
return $c&($a>>$n)
}
下面是这样做的理由
1、有符号右移的过程
2 >>1
2在计算机中存储的二进制表示为
000000000 00000000 00000000 00000010
向右移动1位,高位补0
000000000 00000000 00000000 00000001
结果为1
-2 >>1
负数的存储是以补码的方式存储的(相关知识自行了解),这里简单说明
符号位是 1,-2的表示为
100000000 00000000 00000000 00000010
补码:除符号位外,其他位按位取反,然后 + 1
11111111 11111111 11111111 11111101
11111111 11111111 11111111 11111110
向右移动1位,高位补1
11111111 11111111 11111111 11111111
结果为 -1(转换成10进制后)
注意:移位操作是按照计算机中实际存储的二进制形式进行移动的
2、无符号右移的过程
2 >>1同上
-2 >>1
补码右移1位,高位补 0
01111111 11111111 11111111 11111111
结果是 2147483647
无符号右移 n 位,即把所有位向右移动 n 位(有符号右移),然后把前 n 位变成 0。
要把前 n 位变成 0 ,只需要让其跟一个前 n 位是 0,后 32-n 位是 1 的数进行按位与就可以了。
构造前 n 位是 0 后 32-n 位是 1 的数:利用正数有符号右移高位补 0 实现,这里用 2147483647 这个正数实现(当然其他数也可以),这个数在计算机中的存储前面已经说了,是
01111111 11111111 11111111 11111111
利用这个数构造前 n 位是 0 的数,只需将其向右移动 n-1 位就行了
-2 无符号右移 2位的过程
-2右移2位:11111111 11111111 11111111 11111111
构造数: 00111111 11111111 11111111 11111111
按位与: 00111111 11111111 11111111 111111
在了解位运算之前, 必须先了解一下什么是原码, 反码和补码, 以及二进制与十进制的转换.
原码
一个数在计算机中是以二进制的形式存在的, 其中第一位存放符号, 正数为0, 负数为1. 原码就是用第一位存放符号的二进制数值. 例如2的原码为00000010, -2的原码为10000010
反码
正数的反码是它本身, 负数的反码是在其原码的基础上, 符号位不变, 其余各位取反.
可见如果一个反码表示的是负数, 并不能直观的看出它的数值, 通常要将其转换成原码再计算
补码
正数的补码是它本身, 负数的补码是在其原码基础上, 符号位不变, 其余各位取反, 最后+1. (即负数的补码为在其反码的基础上+1)
可见对于负数, 补码的表示方式也是让人无法直观的看出其数值的, 通常也需要转换成原码再计算.
正整数十进制转二进制
正整数的十进制转二进制的方法为将一个十进制数除以2, 得到的商再除以2, 以此类推知道商为1或0时为止, 倒序取得除得的余数, 即为转换所得的二进制数.
负整数十进制转二进制
负整数的十进制转二进制, 先将该负整数对应的正整数转为二进制, 然后对其取反再+1. 即补码的形式
十进制小数转二进制
十进制小数转二进制的方法为"乘2取整", 对十进制的小数部分乘2, 得到的整数部分即是相应的二进制码数, 然后继续对得到的小数部分乘2, 如此不断重复, 直到小数部分为0或达到精度要求为止. 顺序取得每次的整数部分, 即是该十进制小数的二进制表示.
按位运算符有6个
&: 按位与
|: 按位或
^: 按位异或
~: 按位取反
>>: 右移
<<: 左移
将运算数以二进制表示, 对应位都为1, 则结果为1, 否则为0.
使用场景示例:
判断一个数是奇数还是偶数
奇数的二进制码的最后一位数肯定是1, 而1只有最后一位为1, 按位与运算后, 结果肯定只有最后一位数是1. 而偶数的二进制表示的最后一位数是0, 和1进行按位与运算, 结果的所有位都是0.
将运算数以二进制表示, 对应位有一个为1, 则结果为1, 否则为0.
使用场景示例:
对浮点数向下求整
其实浮点数是不支持位运算的, 所以会先把小数位丢弃, 然后以整数进行位运算, 而任何数与0进行按位或操作, 结果都是它本身, 就好像是对浮点数向下求整.
将运算数以二进制表示, 对应位相同为0, 相异为1.
异或满足交换律和结合律, 数字与它本身进行异或操作, 得到0数字与0进行异或操作, 得到它本身.
使用场景示例:
交换两个变量数字的值
将操作数转换为二进制数, 然后按位求反.
浮点数是不支持位运算的,所以会先直接去除小数部分,转成整数再进行位运算,就好像是对浮点数向下求整.
~~可以进行类型转换,位运算会默认将非数字类型转换成数字类型再进行运算 (转换结果为整数 直接去除小数部分)
使用场景示例:
类型转换
移位运算符将操作数转换成二进制, 然后向左或向右移动, 超过的位丢弃, 空出的位补0.
使用场景示例:
类型转换
任何小数 把它 >>0可以取整
如3.14159 >>0 = 3
其默认将非数字类型的转换为数字类型再做运算的性质与 ~~ , | 0 一样