C语言的本质(2)——二进制、八进制、十六进制与十进制
二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。
19世纪爱尔兰逻辑学家乔治布尔对逻辑命题的思考过程转化为对符号"0''.''1''的某种代数演算,二进制是逢2进位的进位制。0、1是基本算符。因为它只使用0、1两个数字符号,非常简单方便,易于用电子方式实现。
二进制数据的表示法
二进制数据也是采用位置计数法,其位权是以2为底的幂。例如二进制数据110.11,逢2进1,其权的大小顺序为2²、2¹、2º。对于有n位整数,m位小数的二进制数据用加权系数展开式表示,可写为:
二进制数据一般可写为:
例如:将二进制数据111.01写成加权系数的形式。
二进制数据的算术运算的基本规律和十进制数的运算十分相似。最常用的是加法运算和乘法运算。
二进制加法
有四种情况:
0+0=0
0+1=1
1+0=1
1+1=10
0 进位为1
例如求 1011(2)+11(2) 的和
二进制乘法
有四种情况:
0×0=0
1×0=0
0×1=0
1×1=1
二进制减法
0-0=0,
1-0=1,
1-1=0,
0-1=1。
二进制除法
0÷1=0,
1÷1=1。
计算机中的十进制小数转换二进制
计算机中的十进制小数用二进制通常是用乘二取整法来获得的。
比如0.65换算成二进制就是:
0.65 × 2 = 1.3 取1,留下0.3继续乘二取整
0.3 × 2 = 0.6 取0, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
0.2 × 2 = 0.4 取0, 留下0.4继续乘二取整
0.4 × 2 = 0.8 取0, 留下0.8继续乘二取整
0.8 × 2 = 1.6 取1, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
.......
一直循环,直到达到精度限制才停止(所以,计算机保存的小数一般会有误差,所以在编程中,要想比较两个小数是否相等,只能比较某个精度范围内是否相等。)。这时,十进制的0.65,用二进制就可以表示为:0.1010011。
还值得一提的是,在计算机中,除了十进制是有符号的外,其他如二进制、八进制、16进制都是无符号的。
在现实生活和记数器中,如果表示数的“器件”只有两种状态,如电灯的“亮”与“灭”,开关的“开”与“关”。一种状态表示数码0,另一种状态表示数码1,1加1应该等于2,因为没有数码2,只能向上一个数位进一,就是采用“满二进一”的原则,这和十进制是采用“满十进一”原则完全相同。
1+1=10,10+1=11,11+1=100,100+1=101,
101+1=110,110+1=111,111+1=1000,……,
可见二进制的10表示二,100表示四,1000表示八,10000表示十六,……。
二进制同样是“位值制”。同一个数码1,在不同数位上表示的数值是不同的。如11111,从右往左数,第一位的1就是一,第二位的1表示二,第三位的1表示四,第四位的1表示八,第五位的1表示十六。
所谓二进制,也就是计算机运算时用的一种算法。二进制只由一和零组成。
比方说吧,你上一年级时一定听说过“进位筒”(“数位筒”)吧!十进制是个位上满十根小棒就捆成一捆,放进十位筒,十位筒满十捆就捆成一大捆,放进百位筒……
二进制也是一样的道理,个位筒上满2根就向十位进一,十位上满两根就向百位进一,百位上满两根…… 二进制是世界上第一台计算机上用的算法,最古老的计算机里有一个个灯泡,当运算的时候,比如要表达“一”,第一个灯泡会亮起来。要表达“二”,则第一个灯泡熄灭,第二个灯泡就会亮起来。
二进制就是等于2时就要进位。
0=00000000
1=00000001
2=00000010
3=00000011
4=00000100
5=00000101
6=00000110
7=00000111
8=00001000
9=00001001
10=00001010
……
即是逢二进一,二进制广泛用于最基础的运算方式,计算机的运行计算基础就是基于二进制来运行。只是用二进制执行运算,用其他进制表现出来。
二进制与十进制的区别在于数码的个数和进位规律有很大的区别,顾名思义,二进制的计数规律为逢二进一,是以2为基数的计数体制。10这个数在二进制和十进制中所表示的意义完全不同,在十进制中就是我们通常所说的十,在二进制中,其中的一个意义可能是表示一个大小等价于十进制数2的数值。
我们可以将二进制数10表示为:10=1×2^1+0×2^0
八进制
八进制(基数为8)表示法在早期的计算机系统中很常见,因此,偶尔我们还能看到人们使用八进制表示法。八进制适用于12位和36位计算机系统(或者其他位数为3的倍数的计算机系统)。
Octal,缩写OCT或O,一种计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进位,并且开头一定要以数字0开头。八进制的数较九进制的数书写方便,常应用在电子计算机的计算中。
例如:10进制的32表示成8进制就是:040 , 10进制的9,27在八进制中分别记位011,033. 8进制的32表示成10进制就是:3×8^1+2×8^0=26
八进制数不能表示负数和小数,用来表示整数。
八进制(基数为8)表示法在早期的计算机系统中很常见,因此,偶尔我们还能看到人们使用八进制表示法。八进制适用于12位和36位计算机系统(或者其他位数为3的倍数的计算机系统)。但是,对于位数为二的幂(8位,16位,32位与64位计算机系统)的计算机系统来说,八进制就不算很好了。因此,在过去几十年里,八进制渐渐地淡出了。不过,还是有一些程序设计语言提供了使用八进制符号来表示数字的能力,而且还是有一些比较古老的Unix应用在使用八进制。
十六进制
英文名称:hexadecimal number system,是计算机中数据的一种表示方法。同我们日常中的十进制表示法不一样。它由0-9,A-F组成,字母不区分大小写。与10进制的对应关系是:0-9对应0-9;A-F对应10-15;N进制的数可以用0---(N-1)的数表示超过9的用字母A-Z。
10进制的32表示成16进制就是:20
16进制的20表示成10进制就是:2×16¹+0×16º=32
十进制数可以转换成十六进制数的方法是:十进制数的整数部分“除16取余”,十进制数的小数部分“乘16取整”,进行转换。
比如说十进制的0.1转换成八进制为0.0631463146314631。就是0.1乘以8=0.8,不足1不取整, 0.8乘以8=6.4,取整数6 , 0.4乘以8=3.2,取整数3,依次下算。
编程中,我们常用的还是10进制.毕竟C/C++是高级语言。
比如:
int a = 100,b = 99;
不过,由于数据在计算机中的表示,最终以二进制的形式存在,所以有时候使用二进制,可以更直观地解决 问题。但二进制数太长了。比如int 类型占用4个字节,32位。比如100,用int类型的二进制数表达将是:
0000 | 0000 | 0000 | 0000 | 0110 | 0100 |
面对这么长的数进行思考或操作,没有人会喜欢。因此,C,C++ 没有提供在代码直接写二进制数的方法。用16进制或8进制可以解决这个问题。因为,进制越大,数的表达长度也就越短。不过,为什么偏偏是16或8进制,而不其它的,诸如9或20进制呢?2、8、16,分别是2的1次方、3次方、4次方。这一点使得三种进制之间可以非常直接地互相转换。8进制或16进制缩短了二进制数,但保持了二进制数的表达特点。
使用十六进制的意义是:
1 用于计算机领域的一种重要的数制。
2 对计算机理论的描述,计算机硬件电路的设计都是很有益的。比如逻辑电路设计中,既要考虑功能的完备,还要考虑用尽可能少的硬件,十六进制就能起到一些理论分析的作用。比如四位二进制电路,最多就是十六种状态,也就是一种十六进制形式,只有这十六种状态都被用上了或者尽可能多的被用上,硬件资源才发挥了尽可能大的作用。
3 十六进制更简短,因为换算的时候一位16进制数可以顶4位2进制数。
进制转换
1、二进制转十进制
方法:“按权展开求和”
比如:
规律:个位上的数字的次数是0,十位上的数字的次数是1,......,依次递增,而十
分位的数字的次数是-1,百分位上数字的次数是-2,......,依次递减。
注意:不是任何一个十进制小数都能转换成有限位的二进制数。
2、十进制转二进制
· 十进制整数转二进制数:“除以2取余,逆序排列”(除二取余法)
比如:
89÷2 ……1
44÷2 ……0
22÷2 ……0
11÷2 ……1
5÷2 ……1
2÷2 ……0
1
十进制小数转二进制数:“乘以2取整,顺序排列”(乘2取整法)
比如:
(0.625)10= (0.101)2
0.625X2=1.25 ……1
0.25 X2=0.50 ……0
0.50 X2=1.00 ……1
3、二进制数转换成十六进制数:
二进制数转换成十六进制数时,只要从小数点位置开始,向左或向右每四位二进制划分一组(不足四位数可补0),然后写出每一组二进制数所对应的十六进制数码即可。
十六进制数转换成二进制数:把每一个十六进制数转换成4位的二进制数,就得到一个二进制数。
十六进制数字与二进制数字的对应关系如下:
0000 -> 0 0100 -> 4 1000 ->8 1100 -> C
0001 -> 1 0101 -> 5 1001 ->9 1101 -> D
0010 -> 2 0110 -> 6 1010 ->A 1110 -> E
0011 -> 3 0111 -> 7 1011 ->B 1111 -> F
比如:将十六进制数5DF.9 转换成二进制:
5 D F . 9
0101 1101 1111 .1001
即:(5DF.9)16 =(10111011111.1001)2{十六进制怎么会有小数点}
比如:将二进制数1100001.111 转换成十六进制:
0110 0001 . 1110
6 1 . E
即:(1100001.111)2 =(61.E)16
4、二进制数转换成八进制数:从小数点开始,整数部分向左、小数部分向右,每3位为一组用一位八进制数的数字表示,不足3位的要用“0”补足3位,就得到一个八进制数。
八进制数转换成二进制数:把每一个八进制数转换成3位的二进制数,就得到一个二进制数。
八进制数字与二进制数字对应关系如下:
000 -> 0 | 100 -> 4
001 -> 1 | 101 -> 5
010 -> 2 | 110 -> 6
011 -> 3 | 111 -> 7
比如:将八进制的37.416转换成二进制数:
3 7 . 4 1 6
011 111 .100 001 110
即:(37.416)8 =(11111.10000111)2
比如:将二进制的10110.0011 转换成八进制:
0 1 0 1 1 0 . 0 0 1 1 0 0
2 6 . 1 4
即:(10110.0011)2 = (26.14)8
二进制与八进制的互相转换和二进制与十六进制的转换类似,区别在于需要操作的是三位一组而不是四位。
二进制/八进制换算表
二进制 | 八进制 |
000 | 0 |
001 | 1 |
010 | 2 |
011 | 3 |
100 | 4 |
101 | 5 |
110 | 6 |
111 | 7 |
为了将一个二进制数换算为八进制,只需将二进制串划分成每三个位一组(如果需要的话,在前面补零),然后查表2-2,将三位一组的位串替换为相应的八进制数字即可。
只需将八进制数换算为二进制,然后再换算为十六进制即可。
一种计数法,采用0,1,2,3,4,5,6,7八个数码,逢八进位,并且开头一定要以数字0开头。八进制的数较二进制的数书写方便,常应用在电子计算机的计算中。
例如:
10进制的32表示成8进制就是:040
10进制的9,27在八进制中分别记位011,033.
6、八进制化为十进制:
(12.6)8 = 1×8^1 + 2×8^0 + 6×8^-1 = (10.75)10
7、八进制化为二进制:
按照顺序,每1位八进制数改写成等值的3位二进制数,次序不变。
比如:(17.36)8 = (001 111 .011 110)2 = (1111.01111)2
八进制化为十六进制
先将八进制化为二进制,再将二进制化为十六进制。
例:(712)8 = (1110 0101 0)2 = (1CA)16
8、十六进制化为八进制:
先用1化4方法,将十六进制化为二进制;再用3并1方法,将二进制化为8制。
例: (1CA)16 = (111001010)2 = (712)8
说明:小数点前的高位零和小数点后的低位零可以去除。
9、十进制化八进制
方法1:采用除8取余法。
8| 115…… 3
8| 14 …… 6
8| 1 …… 1
结果:(115)10 = (163)8
方法2:先采用十进制化二进制的方法,再将二进制数化为八进制数
比如:(115)10 = (1110011)2 = (163)8
10、十六进制转换十进制
16进制就是逢16进1,但我们只有0~9这十个数字,所以我们用A,B,C,D,E,F这六个字母来分别表示10,11,12,13,14,15。字母不区分大小写。
十六进制数的第0位的权值为16的0次方,第1位的权值为16的1次方,第2位的权值为16的2次方……
所以,在第N(N从0开始)位上,如果是是数 X (X 大于等于0,并且X小于等于 15,即:F)表示的大小为 X×16的N次方。
假设有一个十六进数 2AF5
直接计算就是:
5×160+F×161+A×162+2×163=10997
也可以用竖式表示:
第0位: 5×160=5
第1位: F×16^1=240
第2位: A×162=2560
第3位: 2×163=8192
-------------------------------
10997
此处可以看出,所有进制换算成10进制,关键在于各自的权值不同。
假设有人问你,十进数 1234 为什么是 一千二百三十四?你尽可以给他这么一个算式:
1234 = 1×103+2×102+3×101+4×100