本文通过回顾大家熟悉的十进制,并用二进制跟它对比,让读者能够快速理解二进制和十六进制。
- 〇、前言
- 一、深入理解十进制
- 二、理解二进制
- 三、理解十六进制
- 四、补充信息
- 五、结语
〇、前言
小学毕业的人都知道“十进制”是什么,在理解十进制的基础上,稍加扩展,就能理解二进制、十六进制是什么。
总的来说,只需要理解“十进制”的这三点就行:
- 每个“位”上有0~9共十个可选的
数字
(digit); - 在尾部每加一个0,
数值
(number)变为原来的10倍;- 例如,230是23的十倍;
- 数值的数字数量决定了它的能表示的最大值;
- 例如,两个数字的数值的最大值是99,三个数字的数值的最大值是999。
至于二进制的加减乘除,基本上没人会去心算或者手工计算的,所以其实是没必要去学的。你只需要知道:
- 二进制的加减乘除,学习起来要比十进制容易十倍!
- 因为十进制的个位加法有45种场景(例如1+3=4),而二进制的单个位的加法只有4种场景。
- 那45种场景,就是你小学时要背的那个
加法表
;
- 那45种场景,就是你小学时要背的那个
- 因为十进制的个位加法有45种场景(例如1+3=4),而二进制的单个位的加法只有4种场景。
注:
- 本文中用
数字
表示0到9其中一个数字,而用数值
表示诸如24、60、365等这样的数;- 在英语中,
数字
对应的单词是digit,数值
对应的单词是number;
- 在英语中,
- 在书写上,
6
既可以是“数字6”,也可能是“数值6”,本文中如非特殊说明,默认为后者。
一、深入理解十进制
人们的学习过程的特点是:
- “通过‘已理解’的东西,去理解‘待理解’的东西”。
所以,学习二进制最好的方式,是先弄清楚十进制的一些概念,然后通过它们去理解二进制、十六进制。
1.1、生活中的十进制
大家平时会说:
- 一个星期里有7天;
- 一天有24小时;
- 一小时有60分钟;
- 一年有365天;
- 注:闰年有366天,因为闰年的2月份有29号。
这其中的7、24、60、365等数值,就是“十进制”的记数方法下的数值。
如果把它们按照百位、十位、个位分解,可以这样表示:
数值 | 百位 | 十位 | 个位 |
---|---|---|---|
7 | 0 | 0 | 7 |
24 | 0 | 2 | 4 |
60 | 0 | 6 | 0 |
365 | 3 | 6 | 5 |
把上面表格中的数值,用数学运算表达式
表示的话,就成了这个样子:
数值 | = | 分解 |
---|---|---|
7 | = | 1 * 7 |
24 | = | 10 * 2 + 1 * 4 |
60 | = | 10 * 6 + 1 * 0 |
365 | = | 100 * 3 + 10 * 6 + 1 * 5 |
1.2、对十进制的深入理解
有了上面感性的认识后,下面我们来用学术的方式来理解一下十进制。
首先是定义(来源:维基百科):
十进制是以10为基础数字系统, 是在世界上应用最广泛的进位制。
根据上述定义,我们可以这么理解:
- 使用了十个数字:0到9;
- 注:是1到9九个数字,再加上0这个数字,一共10个数字;
- “逢十进一”,例如,9 + 1 = 10;
- 为什么要“进一”?
- 答:因为在“个位”上只能填0到9其中一个数字,而习惯上0表示“没有”,所以9是最大的“个位数”
数值
了,要再表达“多一个”,就只能“突破个位数”,使用两个数字来组成一个“数字串”来表示了:10;- “10”中的“1”是“十位”上的数字,“0”是“个位”上的数字;
- 对进位加法的理解。例如:
8 + 7 = 15
可以这么理解:= 8 + (2 + 5)
= 8 + 2 + 5
= 10 + 5
= 15
- 上面的2是怎么来的呢?没错,就是10 - 8 = 2,是因为我们“知道”8和7加起来是大于9的,是需要“进位”的,所以就要从7那里取出
10 - 8 = 2
来让8凑够10;
有了上面的理解,再学习一下下面“取值范围”,你就算是理解十进制的本质了,再坚持一下。
1.3 十进制的取值范围
下图是篮球比赛中常用的“记分牌”,每队的分数用两个数字
来记数,想必你也知道了:
- 每支队伍(红队或者蓝队)的分数的取值范围是0 ~ 99。
这里需要注意一下:
- 虽然最大分数是99分,但实际上是表达了“100”种得分情况;
-
0分
也是个分数,如果某支队水平太差了,零分是有可能的;
-
- 如果某支队实力实在太强,那么还是有超过99分的可能的;
- 但此时,记分牌上是没办法把诸如“101分”之类的表达出来,因为只有“两个数字”;
- 必要时,用
01
表示101分,而观众们看了那么久比赛,是“知道、记得”这支厉害的球队是超过了100分的,记分牌上的数值只是十位、个位上的数据,所以,记分牌上的01
其实是“101分”。- 注:这就是
溢出
这个概念的具体表现了,只是计算机不像人那样聪明,没法记住那是“100分以外的分数”,计算机只会把01
当作“数值1”来处理;
- 注:这就是
- 必要时,用
- 但此时,记分牌上是没办法把诸如“101分”之类的表达出来,因为只有“两个数字”;
另外,要留意,考虑记数范围时,是要把0考虑在内的,所以:
- 如果某一门考试满分是100分的话,实际上是有了101种得分的可能;
- 拓展思考:
- 至少要多少人参加这门考试,才能保证一定有至少有两个人的分数是相同的?
- 答案:102人;
- 因为0到100分共有101种可能,需要再多1个人才能保证保证至少有两个人的分数是相同的。
- 至少要多少人参加这门考试,才能保证一定有至少有两个人的分数是相同的?
- 拓展思考:
总结:
- 一个数字可以表示0~9一共十种(10)取值情况;
- 两个数字可以表示00~99一共一百种(100)取值情况;
- n个数字可以表示
10 * 10 * ... * 10 * 10
种情况;- 一共n个10相乘,用数学符号表达就是“10n”,读作“10的n次方”。
- n个数字所能表示的最大的数值是:
- “10n - 1”
- 两个数字的最大值是: 102 - 1 = 99;
- 三个数字的最大值是: 103 - 1 = 999;
二、理解二进制
有了上面对十进制的深入理解,通过对比的方法,就能很容易理解二进制了。
2.1、二进制数值的书写表达方式
因为下文要用到二进制的数值了,所以需要先说明一下表达方式。
在书写或者程序中表达二进制时,如果每次都写“二进制数1010”这样的,就太啰嗦了,所以有人制定了一种表达方式,规则如下:
- 默认情况下,一个或连起来多个数字,表达的是十进制数值;
- 例如:
7、24、365
等;
- 例如:
- 如果要表达二进制数值,前面加
0b
;- 例如:
0b1、0b100、0b1010
等都是二进制数值。
- 例如:
2.2、二进制的数值转换
我们理解一个二进制数值的大小,一般是将其转换为十进制来理解的,因为我们已经习惯了用十进制来思考了。
上文提到,十进制365(和101)可以理解为:
- 365 = 100 * 3 + 10 * 6 + 1 * 5
- 101 = 100 * 1 + 10 * 0 + 1 * 1
相应地,二进制转换为十进制也是使用类似的规则,区别是:
- 十进制是“十进”,采用的是“个/十/百/千/万...”的进位递增;
- 二进制是“二进”,采用的是“1/2/4/8/16/...”的进位递增;
下面以几个二进制数值来举例:
二进制 | “8”位 | “4”位 | “2”位 | “1”位 | 十进制数值 |
---|---|---|---|---|---|
0b1 | 0 | 0 | 0 | 1 | 1 |
0b10 | 0 | 0 | 1 | 0 | 2 |
0b100 | 0 | 1 | 0 | 0 | 4 |
0b1000 | 1 | 0 | 0 | 0 | 8 |
0b1100 | 1 | 1 | 0 | 0 | 12 |
0b1101 | 1 | 1 | 0 | 1 | 13 |
0b1111 | 1 | 1 | 1 | 1 | 15 |
把上面表格的表达方式,用数学运算表达式
表示的话,就成了这个样子:
二进制 | = | 分解 | 十进制数值 |
---|---|---|---|
0b1 | = | 1 * 1 | 1 |
0b10 | = | 2 * 1 + 1 * 0 | 2 |
0b100 | = | 4 * 1 + 2 * 0 + 1 * 0 | 4 |
0b1000 | = | 8 * 1 + 4 * 0 + 2 * 0 + 1 * 0 | 8 |
0b1100 | = | 8 * 1 + 4 * 1 + 2 * 0 + 1 * 0 | 12 |
0b1101 | = | 8 * 1 + 4 * 1 + 2 * 0 + 1 * 1 | 13 |
0b1111 | = | 8 * 1 + 4 * 1 + 2 * 1 + 1 * 1 | 15 |
2.3、二进制与十进制的对比总结
十进制里有0~9十个数字,二进制里只有0和1两个数字。
条目 | 十进制 | 二进制 |
---|---|---|
使用到的数字 | 0, 1, 2,...8, 9 (共十个) | 0、1 (共两个) |
相邻两个数字间的差异 | 10倍 | 2倍 |
n个数字时可表达数值的数量 | 10n个 | 2n个 |
n个数字时的取值范围 | 0 ~ (10n - 1) | 0 ~ (2n - 1) |
举例:
- 相邻每个位间的差异:
- 十进制里,30是3的十倍,300是3的一百倍;
- 二进制里,0b10是0b1的两倍,0b100是0b1的四倍;
- n个数字时的取值范围 (以4为例):
- 十进制里,
0000 ~ 9999
共一万(10000)个数值; - 二进制里,
0b0000 ~ 0b1111
共十六(16)个数值;
- 十进制里,
三、理解十六进制
在理解二进制的基础上,再理解十六进制,只需要转换一些概念就行。
3.1、使用十六进制的原因
计算机运作的基础是二进制(所有数据、程序都是以0和1的组合来保存的),但因为二进制的“粒度”太小,所以在书写上和程序代码中会显得啰嗦,且不便于阅读,所以需要采用另外一种方式来表达。
这就好比,在表达某个人的体重和身高时,人们会说:
- 张三的体重是60千克;
- 张三的身高是1.72米;
而不会说:
- 张三的体重是60000克;(6万克;“克”这粒度太小了)
- 张三的身高是1720毫米;(1米 = 1000毫米)
相应地,因为二进制只用到0和1两个数字,所以表达起来需要很长的数字串才能表达一个较小的数字,例如:
- 数值 168 用二进制表示,是 0b10101000,足足 8 个数字(除了"0b"这个前缀);
因为一个位只能表达0或者1两种情况,“粒度”太小了,占太多书写空间了,并且不好阅读,所以有人就在二进制的基础上发明了十六进制表达方式
;
- 注意:发明的只是新的
表达方式
而不是十六进制,因为十六进制老早就有了,中国古代是“一斤十六两”的,半斤就是八两,所以有“半斤八两”这个成语。
简单来说,就是把四个二进制“数字”为一组,合起来用一个“十六进制”里的“数字”来表达。
具体表达方式,请看下一小节的说明。
3.2、十六进制表达方式
上面提到,十六进制
其实就是把四个二进制数字
组成一组,并以一个十六进制数字
来表达。
既然称之为“十六进制”,就需要有十六个数字。所以,除了十进制的0~9外,还需要引入六个“数字”,当时制定的人就选择了A、B、C、D、E、F一共六个字母。
另外,为了在书写或者源代码中与十进制数值进行区分,采取了加“0x”这样的前缀,例如:
- 0xA8 是十六进制数值,它对应的十进制数值是 168 ;
- 具体怎么计算出168的,请请看下文的具体计算方法;
3.3、十六进制的数值转换
跟理解二进制数值一样,人们一般是将其转换为十进制来理解的,因为我们已经习惯了用十进制来思考了。
十六进制转换为十进制的规则,跟十进制的类比是:
- 十进制是“十进”,采用的是“个/十/百/千/万...”的进位递增;
- 十六进制是“十六进”,采用的是“1/16/256/4096/...”的进位递增;
下面以几个十六进制数值来举例:
十六进制 | “16”位 | “1”位 | 十进制值 |
---|---|---|---|
0x1 | 0 | 1 | 1 |
0xF | 0 | F | 15 |
0x10 | 1 | 0 | 16 |
0x12 | 1 | 2 | 18 |
0xA0 | A | 0 | 160 |
0xA8 | A | 8 | 168 |
0xF0 | F | 0 | 240 |
0xFF | F | F | 255 |
把上面表格的表达方式,用数学运算表达式
表示的话,就成了这个样子:
- 请留意:0xA等于10,0xF等于15 。
十六进制 | = | 分解 | 十进制值 |
---|---|---|---|
0x1 | = | 16 * 0 + 1 * 1 | 1 |
0x8 | = | 16 * 0 + 1 * 8 | 8 |
0xF | = | 16 * 0 + 1 * 15 | 15 |
0x10 | = | 16 * 1 + 1 * 0 | 16 |
0x12 | = | 16 * 1 + 1 * 2 | 18 |
0xA8 | = | 16 * 10 + 1 * 8 | 168 |
0xF0 | = | 16 * 15 + 1 * 0 | 240 |
0xFF | = | 16 * 15 + 1 * 15 | 255 |
3.4、关于十六进制的总结
所以,你可以这样理解十六进制:
- 一个十六进制数字,其实是四个二进制数字的组合,所以一个十六进制数字能表达的数值的数量是:
- 24 = 2 * 2 * 2 * 2 = 16
- 每个“位”上有
0~9、A、B、C、D、E、F
共十六个可选的数字;- 注:在十六进制里,A到F都是“数字”,分别对应于十进制的10~15的数值;
- 在尾部每加一个0,数值变为原来的16倍;
- 例如,0x30(48)是0x3(3)的16倍;
- 数值的数字数量决定了它的能表示的最大值和取值数量;例如:
- 一个数字的数值的最大值是0xF,即15,一共有16种取值;
- 161 = 16;
- 两个数字的数值的最大值是0xFF,即255,一共有256种取值;
- 162 = 256;
- 四个数字的数值的最大值是0xFFFF,即65535,一共有65536种取值;
- 164 = 65536;
- 一个数字的数值的最大值是0xF,即15,一共有16种取值;
四、补充信息
针对上面的描述,补充一些信息:
- 书写二进制数值时,为了工整一般会补足四位;例如:
- “0b110”一般会被写作“0b0110”。
- 书写十六进制数值时,为了工整一般会补足两位或者四位;例如:
- 0x06(补足两位)、0x01FF(补足为四位);
- 实际工作中比较少直接写二进制,而是写其对应的十六进制数;例如:
- 0b0110(6),一般是写0x06(补足为两位);
五、结语
- 通过复习十进制的知识,稍加变化就能理解二进制、十六进制;
- 三种进制的单数字取值范围分别是:
- 单个十进制数字,能表达的最小数值是0,最大数值是9,一共10种取值;
- 单个二进制数字,能表达的最小数值是0b0,最大数值是0b1,一共2种取值;
- 单个十六进制数字,能表达的最小数值是0x0,最大数值是0xF,一共16种取值;
- 因为0也算是一个取值,所以“能表达的数值的数量”和“最大取值”(最大数值)和的关系是:
-
取值的数量
=最大取值
+ 1
-
- 十六进制数值到十进制数值的对应当中,有四个比较常用的值,最好记住:
-
0xF
= 0b1111 =2*2*2*2 - 1
= 24 - 1 = 16 - 1 =15
-
0xFF
= 0x11111111 = 28 - 1 = 256 - 1 =255
- 注:IP地址的
掩码
(例如255.255.255.0),跟这有关系,这里就不展开了;
- 注:IP地址的
-
0xFFFF
= 216 - 1 = 65536 - 1 =65535
-
0xFFFFFFFF
= 232 - 1 = 4294967296 - 1 =4294967295
- 大概记住“比43亿小一点”就行了。
-