3.1 二进制与进制转换 | Binaries And Base Conversion

发布于 2025-09-25  751 次阅读


二进制与进制转换 | Binaries And Base Conversion

在向没有相关背景的读者介绍一门学科时,往往需要一个循序渐进的过程。学习计算机语言也同样如此。前两章里,我们通过一些直观、简洁的概念,帮助初学者初步接触了 C 语言。但在打下基础之后,系统、严谨地理解背后的原理就显得尤为重要。

因此,对于本章的内容,我们将会暂时把重心转向知识的系统化。我们会先讨论一些计算机学科的基础支撑内容,例如二进制和信息的表示与存储;同时,也会把前两章因篇幅限制而未能展开的部分内容(如分支语句中的三元运算符、引用、typedef 等等)补充进来。至于那些难度更高、需要更强抽象能力的主题,例如指针和算法,我们会留到后续章节再来探讨。

一、学习二进制的必要性

在计算机科学中,二进制(Binary)是最基本的数据表示方式。计算机内部使用二进制来存储和处理信息,因为电子设备更容易区分两种状态(如开/关、高电平/低电平)。理解二进制不仅有助于我们更好地理解计算机的工作原理,还能帮助我们在编程中更有效地处理数据。

这一节中,我们暂时将不涉及具体的编程实现,而是专注于理解二进制的概念、表示方法以及与其他进制(如十进制、十六进制)的转换。掌握这些基础知识后,我们才能更深入地理解计算机如何存储和处理数据。

这一节将更偏数学,而不是程序设计。希望你能理解这些概念存在的合理性,并在后续的学习中逐步体会它们的实际应用。

二、二进制的基本概念

小学数学中,我们就听过"逢十进一"的说法。

在小学里学数数的时候:0,1,2,3,4,5,6,7,8,9, ... 在你数到9之后,再往上数一个数,大人们会告诉你:一共只有09十个数字,再往上加数字不够用了,因此要 “进位”(carry)

这就是十进制(Decimal)的概念。我们常用的十进制是基于10的计数系统,使用0到9这十个数字来表示所有的数值。

那么如果这个世界上只有3个数、5个数、7个数呢?我们也可以用类似的方式来表示数值,只不过是三进制五进制七进制而已。

二进制(Binary)则是基于2的计数系统。与十进制使用10个数字计数不同,二进制中仅含有01两个数字,也就是“逢二进一”

0开始数,0, 1, ... 数到1之后,再往上数一个数,数字不够用了怎么办呢,因此要进位。进位后,二进制的表示方式变成了10,这就是二进制中的 “二”

通过数数的方法,我们可以列出自然数的前几个数在二进制和十进制中的表示:

十进制 二进制 十进制 二进制
0 0 4 100
1 1 5 101
2 10 6 110
3 11 7 111

此外,计算机中常用的进制还有十六进制(Hexadecimal)和八进制(Octal)。

值得说明的是:由于人们长期以来都采用十进制的计数方式,对于十六进制中1015的数码本身没有单个字符表示,所以十六进制使用0-9A-F(或a-f 来表示0-15的数值。而八进制则使用0-7来表示0-7的数值。

三、二进制的加法与乘法

1. 二进制加法

仿照十进制加法中,“对位相加、逢十进一”的原则,我们给出二进制加法的定义,即“对位相加、逢二进一”。具体规则由下面的例子简单给出:

        1 0 0 1  (十进制9)
      +   1 0 1  (十进制5)
     -----------
        1 1 1 0  (十进制14)

2. 二进制乘法

仿照十进制乘法中,“逐位相乘、按位排列、逢十进一”的原则,我们给出二进制乘法的定义,即“逐位相乘、按位排列、逢二进一”。例如下面的例子:

        1 0 1 1   (十进制11)
      x   1 0 1   (十进制5)
   -------------
        1 0 1 1   (1011 x 1)
      0 0 0 0     (1011 x 0, 左移一位)
    1 0 1 1       (1011 x 1, 左移两位)
   -------------
    1 1 0 1 1 1   (十进制55)

但这些例子只是常规情况,下面我们介绍一个二进制中特殊的乘法运算:乘以2

由于二进制逢二进一,因此乘以2的结果就是在原数的末尾加一个0,更准确的说法是,把原有的数值左移一位。例如:

     1 0 1 1  (十进制11)
   x     1 0  (十进制2)
  -----------
   1 0 1 1 0  (十进制22)

也因此,在二进制的整数除法中,对于偶数,除以2的结果就是把原数的末尾0去掉,准确说是把原有的数值右移一位。例如:

     1 0 1 1 0  (十进制22)
   /       1 0  (十进制2)
  -------------
     1 0 1 1    (十进制11)

对于末位为1的二进制数,即单数,如果把末尾的1去掉,就是整数除法。例如:

     1 0 1 1  (十进制11)
   /     1 0  (十进制2)
  -----------
     1 0 1    (十进制5)

而我们后面将介绍十进制小数的二进制表示,如果按右移的方式把末尾的1拿入小数点后面,就是小数除法的结果:

     1 0 1 1 . 0  (十进制11)
   /         1 0  (十进制2)
  ----------------
       1 0 1 . 1  (十进制5.5)

与十进制的联系

会不会觉得有些无厘头?但如果我说,对于一个你所熟悉的十进制数,例如123。我现在希望你把它乘以10,你会怎么做?你会不假思索地说:1230,这是因为你自然的在末尾加一个0,或者说,把123整体往前移了一位。这就是十进制的乘以10

同样,对于十进制数123,如果我希望你把它除以10,你会怎么做?你会不假思索地说:12.3,这是因为你自然的把末尾的3拿到小数点后面,或者说,把123整体往后移了一位。这就是十进制的除以10

再看看二进制里的乘以2和除以2,你会发现它们和十进制的乘以10和除以10完全一样的

四、进制转换

我们在上面的部分里,通过数数的方式,列出了二进制和十进制的对应关系。但当我们需要表示更大的数时,手动列出对应关系就不太现实了。我们需要一种系统化的方法来进行进制之间的转换。

我们先来看看我们熟悉的十进制是如何表示数值的。来看下面的例子:

234
 = 200 + 30 + 4
 = 2 \times 10^2 + 3 \times 10^1 + 4 \times 10^0

对于十进制数,我们学习过个位、十位、百位、千位等等的概念。事实上,每一位上的数字表示的是该位数字乘以10的幂次方。

因此对于二进制数,我们也可以用类似的方法来表示。例如我们在刚才数数的例子中看到的二进制数1101,我们可以把它拆解成:

1101_{(2)}
 = 1 \times 2^3 + 1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0

为此,我们给出二进制转十进制的通用方法:

  1. 从右到左,给二进制数的每一位编号,最低位编号为0
  2. 对于每一位上的数字d,计算d * 2^n,其中n是该位的编号;
  3. 将所有位上的结果相加,得到的和即为对应的十进制数。

同样,我们也可以给出十进制转二进制的通用方法:

通过定义,我们不断进行如下操作:

  1. 找到小于该十进制数的最大2的幂次方,记为2^k,该二进制数从右往左的第k + 1位即为1
  2. 该十进制数减去2^k,得到新的十进制数,记为n
  3. 重复上述步骤,直到n0为止。

例如:
154 - 2^7 = 26
26 - 2^4 = 10
10 - 2^3 = 2
2 - 2^1 = 0

因此,154的二进制表示为10011010。这是因为154 = 2^7 + 2^4 + 2^3 + 2^1,故第8542位为1,其余位为0

此外,我们也可以用这种除法法则实现:

  1. 2去除该十进制数,记录下余数(01);
  2. 2去除商,继续记录下余数,直到商为0为止;
  3. 将所有余数倒序排列,得到的结果即为对应的二进制数。

同样以154为例:

154 / 2 = 77 余 0
77 / 2 = 38 余 1
38 / 2 = 19 余 0
19 / 2 = 9  余 1
9 / 2 = 4   余 1
4 / 2 = 2   余 0
2 / 2 = 1   余 0
1 / 2 = 0   余 1

把余数倒序排列,得到10011010

五、十进制小数的二进制表示(较难)

我们前面讨论了整数的进制转换。那么小数呢?我们同样可以通过类似的方法来进行转换。

首先我们仍然观察十进制小数的表示方法。例如:

0.625 = 6 \times 10^{-1} + 2 \times 10^{-2} + 5 \times 10^{-3}

那么,对于一个二进制小数怎么表示呢?二进制小数和十进制小数一样,也是由整数部分和纯小数组成的。二进制小数的数码仍然只能由01组成。例如:

1101.101_{(2)} = 1 \times 2^3 + 1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 + 1 \times 2^{-1} + 0 \times 2^{-2} + 1 \times 2^{-3}

1101.101_{(2)} = 13.625_{(10)}

下面我们简单给出十进制小数转二进制小数的方法:

  1. 找到小数部分的最大2的负幂次方,记为2^-k,该二进制数从左往右的第k位小数即为1
  2. 该小数部分减去2^-k,得到新的小数部分,记为m
  3. 重复上述步骤,直到m0为止,或者达到所需的精度

例如:
0.625 - 2^{-1} = 0.125
0.125 - 2^{-3} = 0
因此,0.625的二进制表示为0.101

值得说明的是,就好比有理数1/3在十进制中是一个无限循环小数一样,也有一大部分有理数在二进制中是无限循环小数。

且对于绝大多数的十进制有限小数,转换成二进制后会变成无限循环小数。例如0.1在二进制中表示为0.00011001100110011...,这是因为0.1无法被表示为2的负幂次方的有限和。

和在十进制中做除法会发现某些数会出现循环不同,二进制的循环不太容易发现。以0.1为例:

0.1 - 2^{-4} = 0.0375
0.0375 - 2^{-5} = 0.00625
0.00625 - 2^{-8} = 0.00234375
0.00234375 - 2^{-9} = 0.000390625

但如果我们以分数的形式写下去:

\frac{1}{10} - \frac{1}{2^4} = \frac{3}{80}
\frac{3}{80} - \frac{1}{2^5} = \frac{1}{160}

注意到\frac{1}{160} = \frac{1}{16 \times 10} = \frac{1}{2^4} \times \frac{1}{10}

即:
\frac{1}{10} = \frac{1}{2^4} \times \frac{1}{10} + \frac{1}{2^4} + \frac{1}{2^5}

记得我们说对一个二进制数除2时,是把所有的数码右移一位吗?这里的结果说明,十进制0.1的二进制表示,是自己的二进制表示本身右移四位后,与0.00011的和。

因此我们可以预见这里有一个循环:0.0001100110011...

这个二进制数满足我们所得到的条件:它是自己的二进制表示本身右移四位后,与0.00011的和。

六、练习与应用

  1. 请用自己的语言解释一下,为什么计算机内部喜欢用二进制表示信息?
  2. 举例说明十进制和二进制表示同一个数字的方式有何不同?
  3. 请将以下十进制数转换为二进制数:45, 100, 255
  4. 请将以下二进制数转换为十进制数:101101, 111000, 1001111
  5. 举例说明什么是左移、右移,并解释其在二进制运算中的意义。

七、总结

通过本章的学习,我们了解了二进制的基本概念、加法与乘法规则,以及进制转换的方法。

掌握这些知识,与我们下一节马上要学习的计算机科学中的数据表示、存储和处理密切相关。希望你能通过练习和应用,进一步巩固对二进制及其相关概念的理解。


这里是 /* Huajidawang */ 的个人主页