编程基础之进制详解

计算机组成原理中的二进制、八进制、十进制、十六进制以及进制转换。

更多相关编程基础内容,请关注博主 Hexo 博文系列:

计算机中信息的存储

编码详解

进制详解

机器数和算术溢出


什么是进制?

在生活中,我们通常都是使用阿拉伯数字计数的,也就是 10 进制,以 10 为单位,逢十进一(满十进一),借一当十,也因为只有 0,1,2、3、4、5、6、7、8、9 十个数字组成的,所以叫做十进制(Decimal)。十进制是在人类社会发展过程中自然形成的,它符合人们的思维习惯,例如人类有十根手指,也有十根脚趾。

那么什么是进制呢?进制也就是 进位制 >>>>

对于任何一种进制(X 进制),进行加法运算时都表示某一位置上的数运算时是逢 X 进一位,进行减法运算时都表示某一位置上的数运算时借一当 X,这就是 X 进制。这种进位制,包含 X 个数字(0 ~ X-1),基数为 X

例如:十进制有 0~910 个数字,基数为 10,在加减法运算中,逢十进一,借一当十;二进制就是逢二进一(借一当二,0~1),八进制就是逢八进一(借一当八,0~7), 十六进制是逢十六进一(借一当十六,0~F),以此类推……


常用进制

计算机常用进制有:二进制、八进制、十六进制。

二进制

二进制(Binary)有 0~12 个数字,基数为 2,在加减法运算中,逢二进一,借一当二。

例如,数字 0110111100、1000001` 都是有效的二进制。

了解计算机组成原理的看客老爷应该知道,在计算机内部,数据都是以二进制的形式存储的,计算机硬件无法识别除了 0/1 以外的任何数(参见:[>>> 编程基础之机器数和算术溢出 <<<]),所以二进制是学习编程必须掌握的基础。

二进制加减法 >>>>

二进制加减法和十进制加减法的思想是类似的:

  • 对于十进制,进行加法运算时逢十进一,进行减法运算时借一当十;
  • 对于二进制,进行加法运算时逢二进一,进行减法运算时借一当二。

下面来演示二进制加减法运算的全过程:

[1] –> 二进制加法1+0=11+1=1011+10=101111+111=1110

[2] –> 二进制减法1-0=110-1=1101-11=101100-111=101


八进制

除了二进制,计算机程序设计语言中还会使用到八进制。

八进制(Octonary)有 0~78 个数字,基数为 8,在加减法运算中,逢八进一,借一当八。

数字 0157147336700125430 都是有效的八进制。

下面来演示八进制加减法运算的全过程:

[1] –> 八进制加法3+4=75+6=1375+42=1372427+567=3216

[2] –> 八进制减法6-4=252-27=23307-141=1467430-1451=5757


十六进制

除了二进制和八进制,计算机程序设计语言中十六进制也经常使用,甚至比八进制还要频繁。

十六进制(Hexadecimal)中,用 A 来表示 10B 表示 11C 表示 12D 表示 13E 表示 14F 表示 15,因此有 0~F16 个数字,基数为 16,在加减法运算中,逢十六进一,借一当十六。

注意,十六进制中的字母不区分大小写,ABCDEF 也可以写作 abcdef

下面来演示十六进制加减法运算的全过程:

[1] –> 十六进制加法6+7=D18+BA=D2595+792=D272F87+F8A=3F11

[2] –> 十六进制减法D-3=A52-2F=23E07-141=CC67CA0-1CB1=5FEF


进制转换

上节我们对二进制、八进制和十六进制进行了说明,这里讲解不同进制之间的转换,这在编程中经常会用到:

将二进制、八进制、十六进制转换为十进制

二进制、八进制和十六进制向十进制转换都非常容易,就是 “按权相加”。所谓 “权”,也即“位权(权重)”。

假设当前数字是 N 进制,那么:

  • 对于整数部分,从右往左看,第 i 位的权重等于 Ni-1
  • 对于小数部分,从左往右看,第 i 位的权重为 N-i0 包含在整数部分)。

更加通俗的理解是,假设一个多位数(由多个数字组成的数)某位上的数字是 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.000110.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


八进制和十六进制的转换

八进制和十六进制之间也极少直接转换。

而且,八进制和十六进制之间转换: 可先其转换为十进制数,再由在十进制数转换为十六进制或者八进制。


Author

Waldeinsamkeit

Posted on

2016-08-01

Updated on

2024-01-13

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.