位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。所以要先了解二进制。
另:本章节详细分析部分有一定难度,建议只学习位运算符的使用方法即可。
二进制
17世纪至18世纪的德国数学家莱布尼茨,是世界上第一个提出二进制记数法的人。用二进制记数,只用0
和1
两个符号,无需其他符号。这一计数方法充分结合了数字电子电路系统的高低电平,在一些系统中,高电平表示1
,低电平表示0
,而有的系统则是高电平表示1
,低电平表示2
。这也是为什么低级语言编写的程序不能跨平台使用的原因。下面两个图可以简单表示两种不同系统的高低电平情况:
进制转换
十进制转二进制
一个十进制数转换为二进制数要分整数部分和小数部分分别转换,最后再组合到一起。
整数部分采用 "除2取余,逆序排列"法。具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。例:125:
经过运算,十进制的125
,转换成二进制之后为1111101
。
小数部分要使用“乘2取整法”。即用十进制的小数乘以2并取走结果的整数(必是 0或1),然后再用剩下的小数重复刚才的步骤,直到剩余的小数为0时停止,最后将每次得到的整数部分按先后顺序从左到右排列即得到所对应二进制小数。例如,将十进制小数 0.8125 转换成二进制小数过程如下:
二进制转十进制
二进制转换成十进制是要按位进行\(2^{x-1}\)运算,再加到一起,比如:
\[(111111)_2 = 2^5 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0 = 63\]
或:
\[(101011)_2 = 2^5 + 2^3 + 2^1 + 2^0 = 43\]
位运算 Bitwise
运算符 | 说明 |
---|---|
~ | 按位取反 |
>> << | 右移 左移 |
& | 按位与 |
^ | | 按位异或、按位或 |
按位取反
按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1:
>>>~6
-7
>>>~-8
7
~x
类似于 -x-1
,但是实际情况远远要复杂得多,有兴趣的同学可以查看附录进行学习附录-按位取反
左移、右移
位运算中,左移n
位相当于原数整除2n
,左移n
位相当于原数乘以2n
,但是位移运算效率更高。
>>>15>>2
3
>>>15<<2
60
假设我们的一台简易计算机只用一个字节(byte,即8位)来存储数值,那么15
的二进制应该为0000 1111
,所以左移2位之后变为0000 0011
,即3
; 左移2位之后变成0011 1100
,即60
。
按位与
按位与运算是将两个数值的二进制按位进行逻辑与运算,只有同时为1
时才能得到1
,否则结果都是0
。
>>>15 & 24
8
15: | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
24: | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
& | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
按位或
按位或运算是将两个数值的二进制按位进行逻辑或运算,只有同时为0
时才能得到0
,否则结果都是1
。
>>>15 | 24
31
15: | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
24: | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
| | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
按位异或
按位异或运算是将两个数值的二进制按位进行逻辑异或运算,当值相同是得到0
,不同时则得到1
。
>>>15 | 24
23
15: | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
24: | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
^ | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 |
总结
位运算是计算机编程中很重要的一种运算方式,这里我们暂时了解这些就足够了。