位运算符
位运算一览表
符号 | 示例 | 含义 |
---|---|---|
& | $a & $b | 按位与。将 $a 和 $b 中都为 1 的位设为 1 |
| | $a | $b | 按位或。将 $a 和 $b 中任何一个为 1 的位设为 1 |
^ | $a ^ $c | 按位异或。将 $a 和 $b 中相同位不一致的位设为 1 |
~$a | ~$a | 按位取反。将 $a 为 1 的位设为 0,为 0 的位设为 1 |
<< | $a << $c | 左移。将 $a 的位向 左 移动 $b 次 |
| $d >> $b | 左移。将 $a 的位向 右 移动 $b 次
& 运算符
按位与。相同为 1,不同为 0
$a = 1; // 0001
$b = 2; // 0010
echo $a & $b; // 0000
按位比较,相同位得1,不同位得 0。由于 1 和 2 的二进制数中每个位都不相同,所以结果为: 0000,也就是 0。
| 运算符
按位或。有 1 为 1,无 1 为 0
$a = 1; // 0001
$b = 3; // 0011
echo $a | $b; // 0011
按位比较,相同位得 0 ,不同位 得 1,所以结果为: 0011,也就是 3。
^ 运算符
按位异或。相同为 0,不同为 1
$a = 1; // 0001
$b = 3; // 0011
echo $a ^ $b; // 0010
按位比较,相同位得 0 ,不同位 得 1,所以结果为: 0010,也就是 2。
~ 运算符
按位取反。1 取 0,0 取 1
$a = 1; // 0000 0000 0000 0000 0000 0000 0000 0001
$a1 = ~$a;
echo $a1; // -2。
这个运算符相比较其它位运算符要复杂一些。我们知道,大多数编程语言中,最高位是符号位,那么,32 位操作系统下,PHP 整数的最大值是:
0111 1111 1111 1111 1111 1111 1111 1111 = 2147483647
因此,当对 1 进行按位取反后,得到
$A1 = 1111 1111 1111 1111 1111 1111 1111 1110
符号位为 1,即为 负数。在计算机中,负数以其对应绝对值的补码形式表达。也就是说,$a1 的补码是 $A1,则
反码 = 补码 - 1 = 1111 1111 1111 1111 1111 1111 1111 1101
那么 $a1 对应的整数就是:
原码 = 反码各位取反 = 0000 0000 0000 0000 0000 0000 0000 0010 = -2;
<< 运算符
各位向左移动,末尾补 0
$a = 2; // 0000 0000 0000 0000 0000 0000 0000 0010
$a1 = $a << 3;
echo $a1; // 16
32 位系统下,一个整数用 32 位表示。当位数向左移动,舍去多余的位数,末尾补 0 ,则得到 $a1 为:
0000 0000 0000 0000 0000 0000 0001 0000 = 16
因此
$a << $b = $a^($b+1) // $a 的 ($b + 1) 次方
左移运算符有一个比较有趣的地方,当一个数向左移动超过计算机指定整数位时,就会出现不符合我们上述总结的原数平方规则的情况。比如 2 在 64 位系统下,向左移动 62、63、64 位:
echo 2 >> 61 // 4611686018427387904
echo 2 >> 62 // -9223372036854775808
echo 2 >> 63 // 0
echo 2 >> 64 // 0
有兴趣的朋友可以列出对应二进制数,推演下计算过程。
>> 运算符
各位向右移动,前面补 0
$a = 8; // 0000 0000 0000 0000 0000 0000 0000 1000
$a1 = $a << 3;
echo $a1; // 16
左移和右移运算符“误区”
关于左移和右移运算符,很多朋友可能会看到这样的总结:
左移平方,右移开方
其实严格来说,这只针对值为 2 的正整数次幂的整数有效。当不是 2 的正整数次幂时,比如:
$a = 9; // 0000 0000 0000 0000 0000 0000 0000 1001
$a1 = $a >> 1;
echo $a1; // 4
所以,遇到左移和右移运算符时,要实际情况实际分析,不能一味的按照别人的总结走。