什么是二进制

引言

我们从小就会数数。

1,2,3,4,5,6,7,8,9,10,11,12 ……
任何一个智力正常的人都能无穷无尽地数下去。

可是你有没有想过,数字难道就只能是这样的吗?
接下来,我们换一种数数方法。
1,10,11,100,101,110,111,1000,1001,1010,1011,1100……

你可能有点摸不着头脑,但这就是刚刚1~12在二进制里的表示。
看完这篇文章,我相信你能彻底理解。

这篇文章从数制写起,讲解了二进制是什么,为什么要用二进制,还讲解了由1和0构成的二进制数是怎么变成我们计算机中的文本、图片、视频的。文章挺长,但耐心读完,我相信你能有所收获。

数字

绝大多数人生来有两双手,每只手有五个手指
当我们还在幼儿时代时,我们就会借助手指来数数了。

人大多数情况下只有十根手指,那么如果想表示大于十的数,该怎么办?
你大概会说:“这不是很简单嘛,可以用数字啊”
古人也是一样的想法,因此创造了各种符号用来表示“数”

现今,我们最常用的是阿拉伯数字。

进制与数字

进制

小学老师教过我们,阿拉伯数字是“满十进一”的,即每当数到了10,就将当前的一位归零,将下一位加上一。
这就是进制
满几进一,就是几进制。

比如阿拉伯数字中,当从0数到9后,下一个数字就不再用新的数字表示,而是将十位写上1,个位写上0,也就是10,这便是十进制,也是绝大部分人日常使用的进制。

而二进制就是“满二进一”,即每当数到了2,就将当前的一位归零,将下一位加上一。 因此,类似于十进制有10个数字,二进制只有两个数字,0和1

“位”的意义

十进制中,对于一个数字中的单个数位,我们有“个位”、“十位”、“百位”、“千位”之称。
其中每个数位,分别代表有多少个$!10^0!$, $!10^1!$, $!10^2!$, $!10^3!$……

如在数字1394中:
“4”位于个位上,代表4个$!10^0!$(一)
“9”位于十位上,代表9个$!10^1!$(十)
“3”位于百位上,代表3个$!10^2!$(百)
“1”位于千位上,代表1个$!10^3!$(千)

合起来,就是$!1\times1000+3\times100+9\times10+4\times1=1394!$

二进制的道理与之相同。
二进制的每个数位,分别代表$!2^0!$, $!2^1!$, $!2^2!$, $!2^3!$……

如在二进制数字1010
第一位的“0”代表 0 个$!2^0!$
第二位的“1”代表 1 个$!2^1!$
第三位的“0”代表 0 个$!2^2!$
第四位的“1”代表 1 个$!2^3!$
全部加起来,就是$!0\times2^0+1\times2^1+0\times2^2+1\times2^3=10!$

在二进制的部分,你可能注意到我没有说“个位”,“十位”,而是说**“第一位”,“第二位”**,这是因为“个位”、“十位”的叫法本身就是对于十进制而言的,因此无法被用于描述二进制的数位,后同。

实践

现在让我们来用十进制和二进制从1开始数数,巩固一下刚刚的知识吧。

  1. 首先是1,这个数字在十进制和二进制都是一样的,略过。

  2. 接下来,到了十进制的2,刚刚我们讲过,二进制“满二进一”,因此我们应该将最低位归零,并在下一位加一,也就是10

  3. 十进制的3呢?很简单,你应该也能想明白,应该是11。

  4. 到了十进制的4,很明显,再加1的话最低位又到了2。因此将最低为归零,并将下一位加一。可是下一位本来就是1啊,那怎么办?很显然,下一位也应该归零,再将第三位加一,最终得到100

这是从3数到4的整个流程:

第三位第二位最低位描述
011原来的数3
011+1加1
01+10发现最低位到2了,于是将其归零,下一位加1
0+100下一位也到2了,再归零,再下一位,即第三位加1
100最终得到100

总结

二进制其实没有那么难,核心思想就「满二进一」,只要懂了这个,你也能向平时数数一样,轻松地用二进制数数。

为什么要用二进制

我相信,看我文章的,大概都对电脑有一定了解吧。

一种简单的说法是,计算机的处理器是电路构成的,而电路中,通电(或高电压,开启)表示1,不通电(或低电压,关闭)表示0,实现起来很简单。

并且,在逻辑中,“真”、“假”两种状态也正好可以用1和0来表示。

二进制在计算机中的具体实现

在计算机中,所有的文字、图片、视屏、网页、文档、软件在计算机眼里,都只是由0和1构成的二进制数据。

字节与比特

计算机中的二进制数据通常以8位二级制数来分割,因此8个二进制数字被称为1个字节 ,1个二进制数字叫1比特

编码

当我们在处理文本、音频、图像等信息时,计算机需要将这些信息转换成二进制数字进行处理。这个过程称为编码

文字编码

简述

说起文本在二进制中的表示方法,就不得不提到文字编码。文字编码是二进制与文字的对应关系,它可以让计算机把某个二进制数字转换为字符,或将字符转换为二进制数。文字编码的核心思想并不复杂,就是一个类似于字典的表,计算机在转换过程中,逐个字符查表即可。

常用的文字编码有ASCII、GBK、GB2312、Unicode等。

文字编码的历史&常见的文字编码

ASCII

计算机是美国人发明的,他们发明电脑时,只想过把自己的26个英文字母装进表中,大写和小写字母,再加上数字和标点符号(其实还有一些控制字符,比如换行、回车、制表符等),7位二进制(十进制最大127)足够了,又预留了一位,刚好1字节(8位)。多出来的一位,后来被欧洲的那些带了变音符号的字母占去了。这就是ASCII(美国信息交换标准代码)。

中文编码

计算机传到了中国,中国人一看,1字节哪够装汉字啊,于是大陆整出了装简体字的GB2312,使用两个字节表达汉字,包括6763个常用汉字(包括一级汉字3755个,二级汉字3008个)。台湾这边呢,整出了装繁体字的Big5(大五码),共收录13060个汉字,同样也用两个字节表示一个汉字。后来大陆还推出过GB2312的“高级版”GBK,它在GB2312的标准上多加了不少生僻字和其它字符,总计有两万多个汉字,但同样以双字节存储。

Unicode

后来,中国有中国的编码,美国有美国的编码,日本有日本的编码,欧洲有欧洲的编码……终于,计算机界的大牛一拍大腿,搞出了Unicode。Unicode是uni前缀(表示“一”“统一”)和code(表示编码)组合而成的词。这表示Unicode的核心理念是包含世界上所有语言的字符,统一所有的编码,最终成为一个世界通用的编码。幸运的是,它做到了。截至2021.09.14发布的Unicode14.0标准,Unicode总共包含144967个字符,囊括了你见过的没见过的知道的不知道的有人用的没人用的……各种语言的字符,当然还包括emoji。

UTF-8(可变长度编码)

之前我们说过,中文编码大多是两个字节,是因为两个字节最多可以装下65535个字符,无论是GB2312的6763个还是GBK的两万多个都绰绰有余,但是到了Unicode时代,理论上是需要四个字节表示的,但是有聪明人想出了可变长度编码这个东西。它可以根据不同的字符来保存不同长度的数据,并且能保证计算机能准确分割。比如英文字符用1字节,中文用3字节,emoji用4字节。(这里中文多出一个字节是因为可变长度编码本身需要浪费一定空间,但是比所有字符均用4字节好得多)

如果你想知道可变长度编码具体是如何实现的,请看下表。

Unicode编码(十六进制)UTF-8字节流(二进制)
000000-00007F0xxxxxxx
000080-00007FF110xxxxx 10xxxxxx
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

表的左边是文字的Unicode十六进制编码,右边是二进制数据,其中x表示有实际用处的数据,其余部分因可变长度编码的实现机制占用。

之前提到,可变长度编码的用处是即使每个字符用不同长度的二进制数据保存,计算机仍然能准确地将一大串二进制数字中分割出每个字符。那么是怎么做到的呢?

很简单,我们看表的右边,每一个Unicode编码范围对应的二进制数据的开头,要么是0,要么是一堆1加一个0。计算机仍按照字节读取,每个字节的开头有几个1,这个字符就占几个字节。

正是可变长度编码的出现,才将Unicode的最大弱点—占用空间大的问题消灭,使得Unicode得以在全世界范围内流行,成为计算机界的“理想编码”。

图片、视频和音频的编码

图片编码

图片的编码方式主要有两种:无损编码和有损编码。无损编码方式可以保留图片的全部信息,但文件通常较大,常用的无损编码方式有GIF和PNG。有损编码方式则通过牺牲部分信息来达到压缩文件大小的目的,常用的有损编码方式有JPEG。

在计算机中,图片以像素阵列的形式存储。每个像素都是由红、绿、蓝三个颜色通道的亮度值组成的。在GIF和PNG这两种无损编码方式中,采用的是基于像素的编码方式,即每个像素的值都单独进行编码。而在JPEG这种有损编码方式中,采用的是基于变换的编码方式,即将像素转换为频域上的变换系数进行编码。

视频编码

视频编码方式通常也采用有损编码方式,以便压缩视频文件的大小。常用的视频编码标准有MPEG-1、MPEG-2、MPEG-4、H.264、H.265等。其中,MPEG-2是用于DVD的标准,MPEG-4则广泛应用于各种流媒体应用。

视频编码的过程主要包括两个步骤:空间预测和变换编码。在空间预测中,每一帧的像素值都是由其前一帧像素值进行预测得到的。这样可以大大减少每一帧需要编码的信息量。而在变换编码中,则采用了和JPEG类似的基于变换的编码方式,将每一帧的像素值转换为频域上的变换系数进行编码。

音频编码

音频编码方式通常也采用有损编码方式,以便压缩音频文件的大小。常用的音频编码标准有MP3、AAC、WMA等。其中,MP3是最为流行的音频编码格式之一,它的压缩率可以达到10:1或者更高。

音频编码的过程主要包括两个步骤:时频变换和熵编码。在时频变换中,将音频信号转换到时域和频域上,以便更好地压缩信号。而在熵编码中,则根据信号的统计特征,采用更有效率的编码方式对信号进行编码。

拓展阅读

其它进制的计算机

其实,在计算机被发明的初期,也有十进制、三进制的计算机。

比如世界上第一台通用计算机ENIAC就是十进制。

而前苏联还曾造过一台三进制计算机Сетунь,它在不同的室温下都表现出惊人的可靠性和稳定性,生产和维护也比同期其它计算机要容易得多。但后来……苏联官僚对这个经济计划外的科幻产物持否定的态度且勒令其停产。 而此时,对Сетунь的订单却如雪片般从各方飞来,但30到50台的年产量远不足以应付市场需求。

很快,计划合作生产Сетунь的工厂倒闭了。1965年,Сетунь停产了。取而代之的是一种二进制计算机,但价格却贵出2.5倍。

最终,这个很有潜力的计算机被扼杀了……

为什么用三进制

其实,理论上e(自然常数,约为2.71828)进制是存储效率最高的进制,但是e毕竟是一个无理数,不太好实现,而3最接近e,因此用了三进制。

至于数学上的证明……略有些复杂,你若感兴趣可以看下一节。

我们只需要知道,三进制能用最少的存储空间保存更多的数据。

进制效率的详解

本节中,对于m进制数x,我们表示为x(m)

我们先举一个例子。

假设我们要用2、3、5、10、16进制表示十进制 0-9999 的10000个数字,每个数制需要多少数位?

因为10011100001111(2)=9999(10)
所以2进制需要14个数位。

因为111201100(3)=9999(10)
所以3进制需要9个数位。

因为304444(5)=9999(10)
所以5进制需要6个数位。

因为9999(10)=9999(10)
所以10进制需要4个数位。

因为270F(16)=9999(10)
所以16进制需要4个数位。

假设,现在要用卡片来表示这些数,每个数制各需要多少卡片?

如:5进制中有0,1,2,3,4五个数字,那么为了表示1位五进制数,我们需要准备5个卡片,也就是1位n进制数需要n个卡片

我们进行简单的乘法即可得知:

2 进制需要$!2\times14=28!$个卡片
3 进制需要$!3\times9=27!$个卡片
5 进制需要$!5\times6=30!$个卡片
10进制需要$!10\times4=40!$个卡片
16进制需要$!16\times4=64!$个卡片

当然,这个过程中出现了「资源浪费」,也就是部分卡片实际可以表达的数比我们规定的上限9999(10)多。

那么,为了准确计算x进制表示n个数时需要用到多少卡片,我们需要用它表示n个数时的「理论位数」,乘以单个数位需要用的卡片数量x。

什么是「理论位数」?之前的例子中,我们说3进制表达9999(10)需要9个数位,这是因为$!log_{3}9999\approx8.3835!$,向上取整得到9;而5进制要6个数位是因为$!log_{5}9999\approx5.7226!$,向上取整得到6。而这个向上取整的过程,就是之前提到的「资源浪费」。而5.7726、8.3835(近似值)则是我们所说的「理论位数」。