发布于

计数系统

作者

学习汇编语言不免要和数字打交道。在这个过程中,我们要用到三种数制:十进制 (Decimal)、二进制 (Binary) 和十六进制 (Hexadecimal)。

二进制计数法

二进制是现代主流计算机使用的基础表示形式。在计算机内部,所有数据都以二进制形式表示,这意味着数字、文字、图像等信息都被转换为由 0011 组成的二进制编码。这种简单的编码方式使得计算机能够高效地处理和存储各种类型的数据,从而实现了计算、存储、通信等各种功能。

Important

在计算机中,二进制对应着高低电平的组合。计算机通过高、低两种电平的组合来表示数字,高电平被认为是 11,低电平被认为是 00

组成二进制数的每个数位称为一个比特 (bit),一个二进制数可以看作一个比特串。数值越大,这个比特串就越长,这也是二进制计数法不好的一面。

二进制转十进制

每种计数法都有自己的数符。十进制有 0,1,2,3,4,5,6,7,8,90, 1, 2, 3, 4, 5, 6, 7, 8, 9 这十个数符;二进制则只有 0,10, 1 这两个数符。这些数符的个数被称为基数。也就是说。十进制有 1010 个基数,而二进制只有两个。

二进制和十进制都是进位记数法。进位记数法的一个特点是:数符的值和它在这个数中所处的位置有关。比如,十进制数 356356,数字 66 在个位上,所以是「6 个」;55 在十位上,所以是「50」;33 在百位上,所以是「300」,即

百位 3 十位 5 个位 6=3×102+5×101+6×100=356\text{百位 3 十位 5 个位 6}={3}\times{10}^{2}+{5}\times{10}^{1}+{6}\times{10}^{0}={356}

由于所处的位置不同,每个数位都有一个不同的放大倍数,称为「权」。每个数位的权是这样计算的(这里仅讨论整数):从右往左开始,以基数为底,指数从 00 开始递增的幂。正如上面的公式所清楚表明的那样,「6」在最右边,所以它的权是以 1010 为底、指数为 00 的幂 100{10}^{0};而 33,它的权则是以 1010 为底、指数为 22 的幂 102{10}^{2}

上面的公式是将 十进制 数转换成 十进制 数,好像没什么用。但是这个公式是可以推广的,可以用它来将二进制数转换成十进制数。

比如一个二进制数 (10110001)B(10110001)_\text{B},它的基数是 22,可以这样来计算与其等值的十进制数:

1×27+0×26+1×25+1×24+0×23+0×22+0×21+1×20=177D{1}\times{2}^{7}+{0}\times{2}^{6}+{1}\times{2}^{5}+{1}\times{2}^{4}+{0}\times{2}^{3}+{0}\times{2}^{2}+{0}\times{2}^{1}+{1}\times{2}^{0}={177}\text{D}

十进制转二进制

为了将一个十进制数转换成二进制数,可以将它不断除以二进制的基数 22,直到商为 00,然后将每一步得到的余数串起来即可。

例如,将十进制数 2626 转换成二进制数 1101011010,可以这样做:

1. 将 26 除以 2,商为 13,余数为 0;2. 用 13 除以 2,商为 6,余数为 1;3. 用 6 除以 2,商为 3,余数为 0;4. 用 3 除以 2,商为 1,余数为 1;5. 用 1 除以 2,商为 0,余数为 1,结束。\begin{array}{l} \displaystyle \text{1. 将 26 除以 2,商为 13,余数为 0;} \\ \text{2. 用 13 除以 2,商为 6,余数为 1;} \\ \text{3. 用 6 除以 2,商为 3,余数为 0;} \\ \text{4. 用 3 除以 2,商为 1,余数为 1;} \\ \text{5. 用 1 除以 2,商为 0,余数为 1,结束。} \end{array}

然后,从下往上,将每一步得到的余数串起来,从左往右书写,就是我们转换后的最终结果了。

Tip

至于为什么 1 除以 2,商为 0,余数为 1\text{1 除以 2,商为 0,余数为 1},那是因为 被除数=除数x商+余数

十六进制计数法

为了解决二进制计数法写起来太长,一点也不方便的问题,人们发明了十六进制计数法。

对于自然数里的前 1010 个,十进制和十六进制的表示方法是一样的。但是,99 之后的数,两者的表示方法就大相径庭了,下面是一张简单的对照表。

十进制十六进制十进制十六进制
001711
111812
221913
332014
442115
552216
662317
772418
882519
99261A
10A271B
11B281C
12C291D
13D301E
14E311F
15F3220
16103321

很显然,一旦某个数字增加到 99 之后,下一次,他将变成 AA,而不是向前进位。因为这里是逢 1616 才进位的。进位只发生在某个数位原先是 FF 的情况下,比如 1F1F,它加 11 后就会变成 2020

Tip

不要惊讶于字母居然可以作为数字。你认为字母不能作为数字只是因为你从小就习惯了这种思想,你只要把它当作一种新型语言来看待就好了。

十六进制转十进制

与二进制转十进制原理相同。即,从右往左开始,以基数为底,指数从 00 开始递增的幂,把每一位都如此相加起来即可。

例如要将十六进制数 (125)H(125)_{H} 转换为十进制,可以这样做:

1×162+2×161+5×160=293D{1}\times{16}^{2}+{2}\times{16}^{1}+{5}\times{16}^{0}=293D

十进制转十六进制

相应地,要将一个十进制数转换为十六进制数,可以采用不断除以基数并取其余数的策略。

例如,要将 293293 转换为十六进制。

1. 将 293 除以 16,商为 18,余数为 5;2. 用 18 除以 16,商为 1,余数为 2;3. 用 1 除以 16,商为 0,余数为 1,结束。\begin{array}{l} \displaystyle \text{1. 将 293 除以 16,商为 18,余数为 5;} \\ \text{2. 用 18 除以 16,商为 1,余数为 2;} \\ \text{3. 用 1 除以 16,商为 0,余数为 1,结束。} \end{array}

最后,从下往上,从左到右书写余数即可。得到 (125)H(125)_{H}

二进制制转十六进制

二进制转十六进制的方法有所不同:将二进制数从右往左,以 4-bit 为一组,分别将每一组的值转换为十六进制即可。

例如,将 (1101 0010 0101 0001)B\text{(1101 0010 0101 0001)}_{B} 转换为十六进制。

因为已经分好组了,所以直接将每一组数都分别转换为十六进制,得到 (D251)H(D251)_{H}

同理,如果看见 (3F8)H(3F8)_{H},我们也可以将它快速的转换为二进制数 (0011 1111 1000)B\text{(0011 1111 1000)}_{B}

我们已经讨论了二进制计数法的缺点,因此,十六进制的优点已经很明显了:既保留了二进制数的直观性,同时写起来还简短。

最后,附上一张部分十进制数、二进制数和十六进制数的对照表。

十进制二进制十六进制十进制二进制十六进制
000000101010A
100011111011B
200102121100C
300113131101D
401004141110E
501015151111F
601106160001 000010
701117170001 000111
810008550011 011137
9100191951100 0011C3