0%

关于二进制

前言

学习二进制及相关运算是计算机学习的重要部分。为了解决我在学习汇编时遇到的问题,我想在这篇博客中梳理并巩固之前所学习的二进制内容,从而更好的往下学习。


进制

进位制又称进制,是一种记数方式,亦称位置记法(positional notation)、数字命位法、定位记法、进位记数法、位值记数法(place-value notation)、位置数值系统(positional numeral system);利用这种“记数法”,可以使用有限种“数字符号”来表示所有的数值。
— wikipedia

我们日常生活中使用十进制进行计算,即为逢十进一,因为一个正常人的手指头为十根,方便我们计数。但是我们在学习其他进制时不需要割去自己的手指,或用上我们的脚趾。

古巴比伦人使用六十进制计算,时至今日仍用作记录 时间, 角度 等。

一进制以1为底数, 与其他进制不同,一进制只有数字 ‘1’, 无法恰当的表示数字0

而计算机使用二进制, 以 0和1 表示, 方便电路信号模拟数字。

进制转换

我们计算时使用十进制,但计算机使用二进制。为了与计算机更好的交流,我们需要使用到进制转换

N进制 -> 十进制:

譬如将二进制数转化为十进制数,将二进制数每一位乘上位权,再乘上这一位的数字,最后相加得到十进制数:

同样的:

十进制->N进制:

将十进制数转换为其他进制数,很方便的一个方法是短除法。

例如将十进制转换为二进制:

1
2
3
4
5
6
7
8
185 / 2 = 92 ...... 1
92 / 2 = 46 ...... 0
46 / 2 = 23 ...... 0
23 / 2 = 11 ...... 1
11 / 2 = 5 ...... 1
5 / 2 = 2 ...... 1
2 / 2 = 1 ...... 0
1 / 2 = 1 ...... 1

将余数从下向上读,
从而我们得到了

同样的:

1
2
3
185 / 8 = 23 ...... 1
23 / 8 = 2 ...... 7
2 / 8 = 0 ...... 2

所以有

数字的存储方式

我们使用十进制运算,而计算机使用二进制。所以我们需要将数字以二进制的形式存入计算机。

显然,对于一个正数或一个无符号数,我们只需要将其转化为二进制存入计算机即可

但对于一个负数,我们需要一些特殊的办法使其能够存入计算机,并且能够正常运算。

位(bit)

位是信息的最小单位,一位只能表示 0或1

符号位和原码

为了表示一个二进制数的正负,我们令这个数字的第一位为符号位,0即为正,1即为负。符号位只表示这个数的正负,不改变它的绝对值。

例如,
这样我们可以用二进制表示一个负数。
同样:

这里的1000 0011和0000 0011都为原码,原码即未经更改的码。

反码

原码只能用来表示一个数,不能直接进行参与运算,原码的符号位必须与其他位分离开,这样做增加了硬件的开销和复杂性。

对于一个简单的 $1 + (-1) = 0$

当我们使用原码计算:

显然我们得到了一个错误答案。

为了进行正确的运算,反码应运而生,一个正二进制数的反码即为它本身,而对于一个负数,它的反码为将它除符号位以外所有的位取反得到的结果。

例如:

对于运算$1 + (-2) = -1$ :

补码

运用反码,我们已经基本可以进行正确的运算了。但是对于之前提到的运算$1 + (-1) = 0$ :

因为1111 1111的符号位为1,所以得到最终结果为-0,但我们又知道0的符号是没有意义的,所以为了解决0的两个编码的问题,我们引入了补码。

正数的补码是它本身,而负数的补码是它的反码 + 1。

例如:

此时我们计算$1 + (-1) = 0$ :

从而,我们在解决0的不同编码问题的同时,得到了正确答案。
同时,我们用1000 0000表示-128而非-0。

所以用补码存储数据时,一个八位数的数据范围为$[-128, 127]$,而当用原码或反码存储时,数据范围为$[-127, 127]$ 。

位运算

位运算对我们来说可能比较麻烦,但对计算机来说,一次位运算要进行的操作数远少于一次加法或其他运算。

与(and, &):

对两个二进制的每一位进行运算, 当两位数都为1时,运算结果为1, 否则为0。

或(or, |):

对两个二进制的每一位进行运算, 当两位数都为0时,运算结果为0,否则为1。

亦或(xor, ^):

对两个二进制的每一位进行运算,当两位数不同时,运算结果为1,否则为0。

非(not,~):

对一个二进制数的每一位,将1变为0, 0变为1。

左移(shl, <<):

将二进制数补码每一位左移一定位数,位移舍弃最高位,低位补0,对二进制数左移一次相当于将这个数乘2。

右移(shr, >>):

与左移相反,向右位移,舍弃低位,高位补符号位。对二进制数右移一次相当于将这个数除以2,向下取整

(ps:c++中整数除法也会自动取整,但 ‘ \ ‘为向零整除,右移运算为向下整除)

我很可爱,请给我钱qwq