编程基础之进制详解
计算机组成原理中的二进制、八进制、十进制、十六进制以及进制转换。
更多相关编程基础内容,请关注博主 Hexo 博文系列:
什么是进制?
在生活中,我们通常都是使用阿拉伯数字计数的,也就是 10 进制,以 10 为单位,逢十进一(满十进一),借一当十,也因为只有 0,1,2、3、4、5、6、7、8、9 十个数字组成的,所以叫做十进制(Decimal)。十进制是在人类社会发展过程中自然形成的,它符合人们的思维习惯,例如人类有十根手指,也有十根脚趾。
那么什么是进制呢?进制也就是 进位制 >>>>
对于任何一种进制(X 进制),进行加法运算时都表示某一位置上的数运算时是逢 X 进一位,进行减法运算时都表示某一位置上的数运算时借一当 X,这就是 X 进制。这种进位制,包含 X 个数字(0 ~ X-1),基数为 X。
例如:十进制有 0~9 共 10 个数字,基数为 10,在加减法运算中,逢十进一,借一当十;二进制就是逢二进一(借一当二,0~1),八进制就是逢八进一(借一当八,0~7), 十六进制是逢十六进一(借一当十六,0~F),以此类推……
常用进制
计算机常用进制有:二进制、八进制、十六进制。
二进制
二进制(Binary)有 0~1 共 2 个数字,基数为 2,在加减法运算中,逢二进一,借一当二。
例如,数字 0、1、10、111、100、1000001` 都是有效的二进制。
了解计算机组成原理的看客老爷应该知道,在计算机内部,数据都是以二进制的形式存储的,计算机硬件无法识别除了 0/1 以外的任何数(参见:[>>> 编程基础之机器数和算术溢出 <<<]),所以二进制是学习编程必须掌握的基础。
二进制加减法 >>>>
二进制加减法和十进制加减法的思想是类似的:
- 对于十进制,进行加法运算时逢十进一,进行减法运算时借一当十;
- 对于二进制,进行加法运算时逢二进一,进行减法运算时借一当二。
下面来演示二进制加减法运算的全过程:
[1] –> 二进制加法:1+0=1、1+1=10、11+10=101、111+111=1110
[2] –> 二进制减法:1-0=1、10-1=1、101-11=10、1100-111=101
八进制
除了二进制,计算机程序设计语言中还会使用到八进制。
八进制(Octonary)有 0~7 共 8 个数字,基数为 8,在加减法运算中,逢八进一,借一当八。
数字 0、1、5、7、14、733、67001、25430 都是有效的八进制。
下面来演示八进制加减法运算的全过程:
[1] –> 八进制加法:3+4=7、5+6=13、75+42=137、2427+567=3216
[2] –> 八进制减法:6-4=2、52-27=23、307-141=146、7430-1451=5757
十六进制
除了二进制和八进制,计算机程序设计语言中十六进制也经常使用,甚至比八进制还要频繁。
十六进制(Hexadecimal)中,用 A 来表示 10,B 表示 11,C 表示 12,D 表示 13,E 表示 14,F 表示 15,因此有 0~F 共 16 个数字,基数为 16,在加减法运算中,逢十六进一,借一当十六。
注意,十六进制中的字母不区分大小写,
ABCDEF也可以写作abcdef。
下面来演示十六进制加减法运算的全过程:
[1] –> 十六进制加法:6+7=D、18+BA=D2、595+792=D27、2F87+F8A=3F11
[2] –> 十六进制减法:D-3=A、52-2F=23、E07-141=CC6、7CA0-1CB1=5FEF
进制转换
上节我们对二进制、八进制和十六进制进行了说明,这里讲解不同进制之间的转换,这在编程中经常会用到:
将二进制、八进制、十六进制转换为十进制
二进制、八进制和十六进制向十进制转换都非常容易,就是 “按权相加”。所谓 “权”,也即“位权(权重)”。
假设当前数字是 N 进制,那么:
- 对于整数部分,从右往左看,第 i 位的权重等于 Ni-1;
- 对于小数部分,从左往右看,第 i 位的权重为 N-i(
0包含在整数部分)。
更加通俗的理解是,假设一个多位数(由多个数字组成的数)某位上的数字是 Y,那么它所表示的数值大小等于 Y × 权重。 怎么理解???看下面实例:
[1] –> 整数部分
例如,将八进制数字 53627(Oct) 转换成十进制:
(八进制)53627 = 5×8^4 + 3×8^3 + 6×8^2 + 2×8^1 + 7×8^0 = 22423(十进制)
从右往左看,第 1 位的位权为 8^0=1,第 2 位的位权为 8^1=8,第 3 位的位权为 8^2=64,第 4 位的位权为 8^3=512,第 5 位的位权为 8^4=4096 …… 第 n 位的位权就为 8^(n-1)。将各个位的数字乘以位权,然后再相加,就得到了十进制形式。
再如,将十六进制数字 9FA8C(Hex) 转换成十进制:
(十六进制)9FA8C = 9×16^4 + 15×16^3 + 10×16^2 + 8×16^1 + 12×16^0 = 653964(十进制)
从右往左看,第 1 位的位权为 16^0=1,第 2 位的位权为 16^1=16,第 3 位的位权为 16^2=256,第 4 位的位权为 16^3=4096,第 5 位的位权为 16^4=65536 …… 第 n 位的位权就为 16^(n-1)。将各个位的数字乘以位权,然后再相加,就得到了十进制形式。
将二进制数字 11010(B) 转换成十进制也是类似的道理:
(二进制)11010 = 1×2^4 + 1×2^3 + 0×2^2 + 1×2^1 + 0×2^0 = 26(十进制)
从右往左看,第 1 位的位权为 2^0=1,第 2 位的位权为 2^1=2,第 3 位的位权为 2^2=4,第 4 位的位权为 2^3=8,第 5 位的位权为 2^4=16 …… 第 n 位的位权就为 2^(n-1)。将各个位的数字乘以位权,然后再相加,就得到了十进制形式。
[2] –> 小数部分
例如,将八进制数字 423.5176 转换成十进制:
(八进制)423.5176 = 4×8^2 + 2×8^1 + 3×8^0 + 5×8^(-1) + 1×8^(-2) + 7×8^(-3) + 6×8^(-4) = 275.65576171875(十进制)
小数部分和整数部分相反,要从左往右看,第 1 位的位权为 8^(-1)=1/8,第 2 位的位权为 8^(-2)=1/64,第 3 位的位权为 8^(-3)=1/512,第 4 位的位权为 8^(-4)=1/4096 …… 第 m 位的位权就为 `8^(-m)。
再如,将二进制数字 1010.1101 转换成十进制:
(二进制)1010.1101 = 1×2^3 + 0×2^2 + 1×2^1 + 0×2^0 + 1×2^(-1) + 1×2^(-2) + 0×2^(-3) + 1×2^(-4) = 10.8125(十进制)
小数部分和整数部分相反,要从左往右看,第 1 位的位权为 2^(-1)=1/2,第 2 位的位权为 2^(-2)=1/4,第 3 位的位权为 2^(-3)=1/8,第 4 位的位权为 2^(-4)=1/16 …… 第 m 位的位权就为 2^(-m)。
将十进制转换为二进制、八进制、十六进制
将十进制转换为其它进制时比较复杂,整数部分和小数部分的算法不一样,分别讲解:
[1] –> 整数部分
十进制整数转换为 N 进制 整数采用 “除 N 取余,逆序排列”法。具体做法是:
- 将 N 作为除数,用十进制整数除以 N,可以得到一个商和余数;
- 保留余数,用商继续除以 N,又得到一个新的商和余数;
- 仍然保留余数,用商继续除以 N,还会得到一个新的商和余数;
- ……
- 如此反复进行,每次都保留余数,用商接着除以 N,直到商为 0 时为止。
演示将十进制数字 36926 转换成八进制的过程 >>>>
从图中得知,十进制数字 36926 转换成八进制的结果为 110076。
演示将十进制数字 42 转换成二进制的过程 >>>>
从图中得知,十进制数字 42 转换成二进制的结果为 101010。
[2] –> 小数部分
十进制小数转换成 N 进制 小数采用“乘 N 取整,顺序排列”法。具体做法是:
- 用 N 乘以十进制小数,可以得到一个积,这个积包含了整数部分和小数部分;
- 将积的整数部分取出,再用 N 乘以余下的小数部分,又得到一个新的积;
- 再将积的整数部分取出,继续用 N 乘以余下的小数部分;
- ……
- 如此反复进行,每次都取出整数部分,用 N 接着乘以小数部分,直到积中的小数部分为 0,或者达到所要求的精度为止。
演示将十进制小数 0.930908203125 转换成八进制小数的过程 >>>>
从图中得知,十进制小数 0.930908203125 转换成八进制小数的结果为 0.7345。
演示将十进制小数 0.6875 转换成二进制小数的过程 >>>>
从图中得知,十进制小数 0.6875 转换成二进制小数的结果为 0.1011。
[3] –> 整数部分 && 小数部分
如果一个数字既包含了整数部分又包含了小数部分,那么将整数部分和小数部分开,分别按照上面的方法完成转换,然后再合并在一起即可。例如:
- 十进制数字
36926.930908203125转换成八进制的结果为110076.7345; - 十进制数字
42.6875转换成二进制的结果为101010.1011。
将十进制数转化为其它进制数无限问题
十进制小数转换成其他进制小数时,结果有可能是一个无限位的小数。
请看下面的例子:
- 十进制
0.51对应的二进制为0.100000101000111101011100001010001111010111...,是一个循环小数; - 十进制
0.72对应的二进制为0.1011100001010001111010111000010100011110...,是一个循环小数; - 十进制
0.625对应的二进制为0.101,是一个有限小数。
但我们知道,计算机内存有限,我们不能用储存所有的小数位数。那么在精度与内存间如何取舍呢???
答案是:在某个精度点直接舍弃,代价就是,计算机内部相应数值不是精准的。
十进制小数在高级程序设计语言中属于浮点类型数据,既然十进制小数存储到内存中有误差,所以计算机中的浮点型数值的计算是不精确的,这种问题 对于所有支持浮点数运算的编程语言都是存在的。
导致什么问题??? >>>> 永远不要直接比较两个浮点的大小!!! >>>> 0.1 + 0.2 不等于 0.3(传送门 –> 为什么 0.1 + 0.2 不等于 0.3?)。
但我们知道:
实际应用中,不同行业,要求的精度不是线性的,我们允许(对结果无关紧要的)误差存在。 10.0001 与 10.001 在铁路工程师看来都是合格的。
二进制和八进制、十六进制的转换
将二进制转换为八进制和十六进制时非常简洁,反之亦然。
[1] –> 二进制整数和八进制整数之间的转换
1)二进制 >>>> 八进制
二进制整数转换为八进制整数时,每三位二进制数字转换为一位八进制数字,高位不足三位用零补齐,注意从低位向高位依次进行。
下图演示如何将二进制整数 1 110 111 100 转换为八进制:
从图中可以看出,二进制整数 1 110 111 100 转换为八进制的结果为 1674。
2)八进制 >>>> 二进制
八进制整数转换为二进制整数时,思路是相反的,每一位八进制数字转换为三位二进制数字,注意从低位向高位依次进行。
下图演示了如何将八进制整数 2743 转换为二进制:
从图中可以看出,八进制整数 2743 转换为二进制的结果为 10 111 100 011。
[2] –> 二进制整数和十六进制整数之间的转换
1)二进制 >>>> 十六进制
二进制整数转换为十六进制整数时,每四位二进制数字转换为一位十六进制数字,高位不足四位用零补齐,注意从低位向高位依次进行。
下图演示了如何将二进制整数 10 1101 0101 1100 转换为十六进制:
从图中可以看出,二进制整数 10 1101 0101 1100 转换为十六进制的结果为 2D5C。
2)十六进制 >>>> 二进制
十六进制整数转换为二进制整数时,思路是相反的,每一位十六进制数字转换为四位二进制数字,注意从低位向高位依次进行。
下图演示了如何将十六进制整数 A5D6 转换为二进制:
从图中可以看出,十六进制整数 A5D6 转换为二进制的结果为 1010 0101 1101 0110。
八进制和十六进制的转换
八进制和十六进制之间也极少直接转换。
而且,八进制和十六进制之间转换: 可先其转换为十进制数,再由在十进制数转换为十六进制或者八进制。
install_url to use ShareThis. Please set it in _config.yml.