02.数字与进制
数字的产生
文明萌芽之前,人类的祖先还没有「数」的概念。然而人类终究是要与较大的数打交道的,除了每天的吃喝拉撒,祖先们渐渐需要面对「打到了多少猎物」、「部落有多少人口」这类简单的统计问题。他们开始动用身上的各种部位,例如手指与脚趾。后面也曾用石子、结绳计数等方式。
假定某个人有4只猫,他可能画4只猫作为记录。
当然,每增加一只猫,就画一只猫,可能太麻烦了;我们能不能用一条竖线来表示呢?可以的,例如:| | | | 表示4只猫
但若某人有27只猫,用画27个竖线来表示猫的只数的方法就显得很荒谬了:
| | | | | | | | | | | | | | | | | | | | | | | | |
于是,古人们想到得有一种更好的办法才行,进制就这样诞生了。我们日常生活中都是用阿拉伯数字,当一位数表示不了的情况下,我们就会进位,也就是从一位数变成两位数,再进位到三位数,以此类推。这个进位规则可以 理解为“逢十进一”。
一个数字依据位置的不同代表不同的数量。数字的位置和数字的大小一样,都是很重要的。(但实际上,数字的位置更重要。)100和1000000中都只有一个1,但我们知道一百万比一百要大得多。
什么是数字系统
到了现代,我们经常用阿拉伯数字来表示数量,例如一辆车,我们用1表示,两辆车,我们用2表示。但其实,0,1,2,3,4,5,6,7,8,9, 这十个数字,都是符号而已。符号不仅仅可以用于表示数量,也可表示事物。例如我们说“3号选手”, 这里的3就是指某个人;又例如2022年3月19号,这里的3指的是3月。
有没其他符号可以表示 ”数量2“ 这个概念呢? 有的。比如在罗马数字中,1~20分别为:Ⅰ、Ⅱ、Ⅲ、Ⅳ、Ⅴ、Ⅵ、Ⅶ、Ⅷ、Ⅸ、Ⅹ、Ⅺ、Ⅻ、XIII、XIV、XV、XVI、XVII、XVIII、XIX、XX。也就是说,对于数量的表示而言,我们用什么符号(阿拉伯数字、罗马数字)都是可以的,只要人们能理解它。比如完全可以约定,J是11,Q是12, K是13(在扑克牌中用到)
在国内,对数字的表示也可以用中文,例如壹贰叁肆伍陆柒捌玖,纸币上就有写明。
在法国,不同数字的表示如下:
什么是标准数字系统
如果各国都采用各自的数字系统,那么国家之间沟通数字是很困难的。例如我们可能看不懂法国的单词表,法国人也看不懂我们的壹贰叁肆伍陆柒捌玖,有没这样一个数字系统,全球各地通用的呢?
有,就是阿拉伯数字,在全世界大部分范围内,阿拉伯数字都是被人们所知道的。也就是说,阿拉伯数字是一种标准。
标准的好处在于,全世界的人都知道,不用担心引起误解。比如在罗马数字中,Ⅹ代表数字10,但如果不事先说明这是罗马数字,人们也可能认为这是一个英文字母X。
数字的其他含义
数字并不仅仅用于做计算。例如在长跑比赛时,为了识别运动员,通常会给每一位运动员编一个号码,线人,这些号码仅仅表示不同的运动员而已,没有数量大小的含义。
十进制介绍
英文为Decimal System,缩写Dec或D
十进制中,不同位置的数字,代表的值是不一样的,例如下面的1:
12 = 1×10 + 2 这里的1代表10
120 = 1×100 + 2×10 这里的1代表10 × 10 = 100
1200 = 1×1000 + 2×100 这里的1代表10 ×10 ×10 = 1000
每个1的乘数是不一样的,乘数也可以理解为权重(权值)。12里的1,权值是101, 120里的1,权值是102, 1200里的1,权值是103。注意,个位数的值可以看成是 个位数 × 10的0次方,因为任何数的0次方都等于1,所以也可以写成
12 = 1×10的1次方 + 2×10的0次方
120 = 1×10的2次方 + 2×10的1次方
1200 = 1×10的3次方 + 2×10的2次方
越高位的数字,权重越大。每个乘数都比右边大十倍(也就是乘以十)。
千位数 | 百位数 | 十位数 | 个位数 |
---|---|---|---|
1000(10的3次方) | 100(10的3次方) | 10(10的1次方) | 1(10的0次方) |
以此类推,一万和一百万,乘数也不同,但都是10的次方。
注意,小数部分也是这样,只不过是10的 负 N次方。
0.75 = 7×10的负1次方 + 5×10的负2次方
在十进制中,十也称为基数。
八进制介绍
八进制的英文:Octal,缩写为O 或者o (英文字母的o)
如果,如果人类像卡通人物那样,每只手上只有 4个手指会怎样呢?我们可能就不是用十进制,而是八进制。当要表示超过 “八”这个概念的数字,我们需要进位,逢八进一。例如
要表示的数量 | 数字 |
---|---|
一 | 1 |
二 | 2 |
三 | 3 |
.... | ... |
七 | 7 |
八 | 10 (逢八进一) |
注意,这里的每个数权重不一样了;
[12]八进制 = 1×8 + 2 , 这里的1 代表8
[122]八进制 = 1×64 + 2×8 + 2 =[82]十进制, 这里的1代表8 × 8 = 64
在[122]八进制 中,从左到右 每个位的乘数 分别是 64,8,1 ,每个乘数都比右边大八倍(也就是乘以八)。
除了十进制,还有十六进制、八进制和二进制等等常用的进制,在人类早期文明历史中,玛雅人采用的还是二十进制。
在八进制里,基数是八,其他进制的基数同理。为了表示是八进制的数字,我们可以用括号将数字包住,并且用下标表明这是几进制,例如八进制的12: (12)8
二进制介绍
二进制的英文:Binary,缩写为B
二进制,是计算机内采用的标准数字系统。
而最简单的进制系统中,无疑是二进制,逢二进一,也是计算机中采用的进制。可以说,计算机只认识二进制,只处理二进制,像我们看到的文本、图像、视频、各种软件等等,最终都会转化为二进制让计算机处理。
要表示的数量 | 数字 |
---|---|
一个 | 1 |
二个 | 10 = 1+1 (逢二进一) |
三个 | 11 = 10 +1 |
四个 | 100 = 11+1 |
.... | ... |
七个 | 111 |
八个 | 1000 = 111 + 1 |
例如 [111] 二进制中,每位数的乘数也不一样了,每个乘数是右侧乘数的两倍。二进制的 111 = 1×4 + 1×2 + 1×1, 也就是说二进制的 111 等于 十进制的7。
111 = 1×4 + 1×2 + 1×1
= 1×2的2次方 + 1×2的1次方 + 1×2的0次方
当二进制的位数很多时,一连串看起来有点头皮发麻,所以一般每隔4为就用一个空格分割。
同理,十进制也有这样的习惯,例如每隔3位用逗号分割,这叫三位分节法,例如1,000 1,000,000
拿二进制数 1011 0110 举例,我们可以用相同的方法转成十进制。
1011 0111 (二进制) =
1x128 + 0x64 + 1x32 + 1x16
+0x 8 + 1x4 + 1x2 + 0x1
=182 (十进制)
二进制的加减乘除:
从上面的例子中可以看到二进制算术运算的两个特点,即二进制数的乘法运算可以通过若干次的“被乘数(或零)左移1位”和“被乘数(或零)与部分积相加”这两种操作完成;而二进制数的除法运算能通过若干次的“除数右移1位”和“从被除数或余数中减去除数”这两种操作完成。
如果我们再能设法将减法操作转化为某种形式的加法操作,那么加、减、乘、除运算就全部可以用“移位”和“相加”两种操作实现了。利用上述特点能使运算电路的结构大为简化。这也是数字电路中普遍采用二进制算术运算的重要原因之一
十六进制
十六进制的英文:Hexadecimal,缩写为X
如果说要用超过十进制的进制,例如十六进制,需要一个符号来代表 “十” 这个概念,人们用 字母来表示 “十 到 十五” 之间的数。
要表示的数量 | 数字 |
---|---|
一个 | 1 |
二个 | 2 |
三个 | 3 |
四个 | 4 |
.... | 5 |
六个 | 6 |
七个 | 7 |
八个 | 8 |
九个 | 9 |
十个 | A |
十一个 | B |
十二个 | C |
十三个 | D |
十四个 | E |
十五个 | F |
十六个 | G |
也就是说 [A]十六进制 = [10] 十进制
[10]十六进制 = 1×16 + 0 = [16] 十进制,进位规则是逢十六进一。
不同进制的对照表
十进制 | 二进制 | 八进制 | 十六进制 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
2 | 10 | 2 | 2 |
3 | 11 | 3 | 3 |
4 | 100 | 4 | 4 |
5 | 101 | 5 | 5 |
6 | 110 | 6 | 6 |
7 | 111 | 7 | 7 |
8 | 1000 | 10 | 8 |
9 | 1001 | 11 | 9 |
10 | 1010 | 12 | A |
11 | 1011 | 13 | B |
12 | 1100 | 14 | C |
13 | 1101 | 15 | D |
14 | 1110 | 16 | E |
15 | 1111 | 17 | F |
各个进制的表示前缀
我们之前为了表示是八进制的数字,我们可以用括号将数字包住,并且用下标表明这是几进制,例如八进制的12: (12)8
也可以有这样的表示方法:给数字加个前缀。这里的前缀就是取各进制的英文首字母,大小写都可以。
进制基数(radix) | 前缀 | 示例 |
---|---|---|
二进制 binary | 0b 0B | 0b11 = 2+1=3 |
八进制 octal | 0o 0O | 0o11 = 8+1=9 |
十进制 decimal | 无前缀 | 11 = 11 |
十六进制 hex | 0x 0X | 0x11 |
进制转换
二进制与十进制
二进制转十进制:只需将每位数乘以对应的乘数,再将结果相加即可。
例如 (1011.01)2 = 1×23 + 0×22 + 1×21 + 0×2-1 + 1×2-2 = (11.25)10
十进制转二进制:采用"除 2 取余,逆序排列"法:
1.首先用 2 整除一个十进制整数,得到一个商和余数
2.然后再用 2 去除得到的商,又会得到一个商和余数
3.重复操作,一直到商为小于 1 时为止
4.然后将得到的所有余数全部排列起来,再将它反过来(逆序排列)
举例:将 (173)10 转为二进制
原理是什么呢? 我们可以推理下。前面我们知道二进制数转十进制数是怎么转换的: (1011.01)2 = 1×23 + 0×22 + 1×21 + 0×2-1 + 1×2-2 = (11.25)10
我们可以用一个通用公司来说明:假设十进制整数为 (S)10 ,其转换为二进制数,值为 (knkn-1 ………… k0)2 ,我们可以列出这样的公式:
(kn×2n + kn-1 ×2n-1 + ………… k0 × 20 )2 = (S)10
我们将等号两边同时除以2,可以得到商为 (kn×2n-1 + kn-1 ×2n-2 + ………… k1 )2 ,余数为k0 (因为1个二进制数最多表示1,除以2肯定是除不尽的,会有余数);也就是说,我们计算出了第一个二进制数是k0;
再次将等号两边同时除以2,可以得到余数k1 …………以此类推,就可以求得二进制数的每一位了!
小数转二进制:采用"乘 2 取整,顺序排列"法:
1.用 2 乘十进制小数,可以得到积,将积的整数部分取出
2.再用 2 乘余下的小数部分,又得到一个积,再将积的整数部分取出
3.重复操作,直到积中的小数部分为零,此时 0 或 1 为二进制的最后一位,或者达到所要求的精度为止
例如将 0.125 转换为二进制:
0.125 * 2 = 0.25 ------0
0.25 * 2 = 0.5 ------0
0.5 * 2 = 1.0 ------1
当小数部分为 0 就可以停止乘 2 了,然后正序排序就构成了二进制的小数部分:0.001
其原理,和十进制转二进制的原理一样。
如果又有整数又有小数:将整数部分和小数部分先单独转为二进制,再合在一起就可以了。
二进制与十六进制
由于4位二进制数恰好有16个状态,而把这4位二进制数看作一个整体时,它的进位输出又正好是逢十六进一,所以只要从低位到高位,将整数部分每4位二进制数分为一组,并代之以等值的十六进制数,
同时从高位到低位将小数部分的每4位数分为一组并代之以等值的十六进制数,即可得到对应的十六进制数。
例如,将(01011110.10110010)化为十六进制数时可得
若二进制数整数部分最高一组不足4位时,用0补足4位:小数部分最低一组不足4位时,也需用0补足4位。
十六进制转二进制,只需反过来,每一位十六进制数用等值的4位二进制数代替就行。例如,将(8FA.C6)16 转为二进制:
二进制与八进制
与十六进制和二进制,互相转换基本一样。
在将二进制数转换为八进制数时,只要将二进制数的整数部分,从低位到高位每3位分为一组,并代之以等值的八进制数,同时将小数部分从高位到低位每3位分为一组并代之以等值的八进制数就可以了。
二进制数最高一组不足3位或小数部分最低一组不足3位时,仍需以0补足3位。
例如,若将(011110.010111)2化为八进制数,则得到
反之,若将八进制数转换为二进制数,则只要将八进制数的每一位代之以等值的3位二进制数即可。例如,将(52.43)8 转换为二进制数时,得到
其他进制
8进制转10进制、16进制转10进制:就只能按权重展开后,相加得到十进制了;
10进制转8进制、10进制转16进制,可以先转为2进制,再分组转换。
进制转换工具
如果我们已经知道如何转换进制了,当数字很大的时候,自己转换就是浪费时间,并且容易出错,因此,我们可以借住计算机帮助我们转换。
win10自带的计算机,按下快捷键win + R,输入 calc 然后回车。然后菜单栏里选择程序员
练习
- 手动实现各进制下的转换
- 自行实现在各进制下的加减乘除
- 用计数器验证结果
参考资料
《编码的奥秘》
《数字电子技术基础》 阎石第五版
【计算机科学速成课】40集全/精校] - Crash Course Computer Science ~-bilibili