早自原始社会起,想必人类就有了计数的需要。男人们捕获了渔猎,女人们采摘了果实,要分配给族群里的成员,就需要进行计数了。
曾经,无论人们使用石子或者骨骼等实物计数,还是结绳计数、刻痕计数、写“正”字计数等等,都有一个共同的缺点:当计数规模比较大的时候,这些计数法因为成本过高、有失便利,就不堪用了。
后来,人们发明了进位计数法。进位计数法可以使用较少数量的数字表示较大范围的数值,一定程度上克服了上述计数法的缺点,成为人们如今普遍使用的计数法。虽然常见的进位计数法有二进制、八进制、十进制、十六进制等,但居于核心地位的是十进制,也是使用最广的进位计数法;二进制、八进制、十六进制多在计算机科学中使用。
一、进位计数的原理
进位计数法中,计数使用的一定数目的符号,叫做数码。十进制有0123456789共10个数码,二进制有01共2个数码,八进制有01234567共8个数码,十六进制有0123456789ABCDEF共16个数码(依次表示0到15)。数码的个数叫做基数,或许是取“基础符号数”的意思。不难发现,数码的个数有几个,基数就是几,也就是几进制。
如何用有限的数码表示无限的数值呢?这就需要借助数位了。数位就是数码的相对位置。任一数位都只能使用基数个数码计数,每当某一数位(本位或低位)的数值超出基数时,则将该数位的数码置为零,在与该数位相邻的数位(进位或高位)增加一,简称“逢基数进一”。所谓本位与进位,低位与高位均是相对而言的。为了与通行的从左至右的书写和阅读顺序相适应,相对靠左的数位为高位,相对靠右的数位为低位。
让我们通过数一数来彻底搞懂进位计数法究竟是如何计数的。
在十进制中,从一数到九,可以分别用数码123456789表示,只需要一个数位。当数到十的时候,是第一次遇到基数十,按计数规则要“逢十进一”,则将9所在数位的数码置为零,而在相邻的高位增加一,于是就有了10,就需要两个数位。数到十一的时候只需要在十的基础上加一,也就是11。以此类推,这两个数位可以从十一数到九十九,即11到99,兹不赘述。当数到一百的时候,低位的9增加一而再次逢十,需置零进一;而高位的9增加一则也再次逢十,也要置零进一;于是经由连续进位就有了100,也就变成了三个数位。
大家对十进制是如此的熟悉,上述关于十进制的解释说明或许是太过啰嗦了。但是,快速掌握其他进制的一个诀窍,就是以进位计数法的计数规则仔细的重新审视我们无比熟悉的十进制。如果对其他进制有什么困惑,那么不妨回到十进制中去寻找答案。
二进制只有0和1两个数码,计数时逢二便要进一。所以,一是1,二需置零进一,便是10,三是11,四则又需要置零进一,便是100,以此类推,兹不赘述。八进制逢八进一,十六进制逢十六进一,在原理上与十进制、二进制并没有什么不同。
进位计数法的原理并不复杂,可以类比于这样一个形象的过程:假定有一堆糖果,我们将每块糖果都装入一个小袋子里,把每N个小袋子装进一个大袋子里,再把每N个大袋子装进一个更大的袋子里……最后,我们依次记录下规格(容量)由大到小的每种袋子的数量,不就可以用袋子的数量表示糖果的数量了吗?这其中的N就是基数,决定着采取哪种进制。
二、进制的转换
(一)其他进制转换十进制
人们习惯于用十进制表示日常生活中接触到的数值,这导致人们只擅长使用十进制计数。当遇到其他进制的数字时,总是要把他转换成十进制的数字,人们才容易理解。例如,当我们说某人的身高是二进制10110100厘米,或者八进制264厘米,或者十六进制B4厘米,我们的头脑中对这个人的身高还是毫无概念,当我们说某人的身高是180厘米的时候,他高大的形象会立刻浮现在我们的脑海中。
为了把其他进制的数字转换成十进制,就需要引入位权的概念。某数位的位权是指该数位所表示的单位数值的十进制表示。进位计数法中,不同数位的相同数码,代表的数值是不同的,这也是进位计数法的优势所在。刻痕计数时画六条竖线,这六条竖线就只能表示六,其中任何一条竖线都表示一。而在进位计数法中,数字111111因进制不同而表示不同的数值,这六个1所表示的数值毫无疑问也是各不相同的。
因为十进制频繁使用、非常重要,所以,十进制中的每一个数位都有专用的名称。整数部分由低到高依次是个位、十位、百位、千位、万位……小数部分由高到低依次是十分位、百分位、千分位、万分位……而二进制、八进制、十六进制则统统没有这样的待遇,他们的数位一律是用整数顺序命名的。具体来说,整数部分最右边的数位,也就是小数点左侧的第一个数位命名为0位,0位的左边依次是1位、2位、3位……0位的右边依次是-1位、-2位、-3位……
Ø在十进制中:
个位的数值增加一,所表示的数值增加一,所以,个位的位权为1。
十位的数值增加一,所表示的数值增加十,所以,十位的位权为10。
以此类推,百位、千位、万位……的位权依次为100、1000、10000……
Ø在二进制中:
0位的数值增加一,所表示的数值增加一,所以,0位的位权为1。
1位的数值增加一,所表示的数值增加二,所以,1位的位权为2。
2位的数值增加一,所表示的数值增加四,所以,2位的位权为4。
以此类推,3位、4位、5位……的位权依次为8、16、32……
Ø在八进制中,0位、1位、2位、3位……的位权依次为1、8、64、512……
Ø在十六进制中,0位、1位、2位、3位……的位权依次为1、16、256、4096……
由是,我们可以得出这样的规律:在N进制中,第i位的位权为Ni。需要特别注意的是,整数部分数位编号i是从0开始的。另外,虽然上述都以整数举例,但在涉及到小数时这一规律同样是适用的,即-1位、-2位、-3位……的位权依次为N-1、N-2、N-3……
在知道位权之后,要把任何一个其他进制的数转换成十进制就变得简单了,只要将各个数位的数码与位权的乘积都加起来就可以啦。例如:
结合前面糖果的例子来理解,位权就是描述袋子规格(可以装入的糖果数)的十进制数,想要知道所有袋子里一共装了多少糖果,只要用袋子的规格乘以袋子的数量算出每种袋子装了多少糖果,再把他们加起来不就大功告成了吗?
(二)十进制转换其他进制
有时基于特别的用途,我们也需要把十进制转换为其他进制。我们设待转换的十进制数的整数部分为X,小数部分为Y,如果我们要把他转换成N(基数)进制的数,那么具体方法如下:
Ø整数部分的转换
先用整数X除以基数N,得到商X0和余数R0;
再用商X0除以基数N,得到商X1和余数R1;
再用商X1除以基数N,得到商X2和余数R2;
再用商X2除以基数N,得到商X3和余数R3;
……
以此类推,直至商Xp为0,得到余数Rp。
Ø小数部分的转换
先用小数Y除以N-1(等同乘以N),得到小数部分Y-1和整数部分R-1;
再用小数Y-1乘以N,得到小数部分Y-2和整数部分R-2;
再用小数Y-2乘以N,得到小数部分Y-3和整数部分R-3;
……
依次类推,直至小数Y-q为0或者达到所需的精度,得到整数部分R-q。
Ø将以上求得的R按照角标由大到小的顺序排列起来,就可以得到转换后的N进制数,即:Rp……R3R2R1R0R-1R-2R-3……R-q。
上述转换方法,对于整数部分而言,可以归纳为“连除基数,倒序取余”;对于小数部分而言,可以归纳为“连乘基数,正序取整”。
例如,我们要把十进制数2525.885转换为八进制数,该怎么做呢?我们先用整数部分连续除以基数8而倒序取余数,再用小数部分0.885连续乘以基数8而正序取整数,最后把他们连接在一起就可以得到结果了。
所以,十进制数2525.885转换为八进制数的结果近似等于4735.705。
为什么采取上述方法就可以将十进制数转换为其他进制呢?请允许我结合前面糖果的例子来试着解释说明一番。
我们将一个十进制数转换为其他进制,相当于将糖果从一些规格(十进制)的袋子里重新分装到另外一些规格(新进制)的袋子里。
我们用十进制数的整数部分除以新进制的基数(新进制的1位的位权),相当于假设将全部的糖果都暂时装进规格等于新进制的基数的袋子里,得到的商就是能够装满的袋数,剩余的糖果只能装入规格等于1(新进制的0位的位权)的袋子,所以得到的余数就是新进制0位的数码。我们用上一步得到的商继续除以新进制的基数,相当于将那些规格等于新进制的基数的小袋子全部暂时装入规格更大(新进制的2位的位权,即基数的平方)的大袋子里,得到的商就是能够装满大袋子的数量,得到的余数就是新进制1位的数码。以此类推,直到商为0的时候,我们就可以得到新进制数整数部分各个数位的数码。
我们用十进制数的小数部分除以新进制的基数的倒数(新进制的-1位的位权),相当于假设将全部的糖果都暂时装进规格等于新进制的基数的倒数的袋子里,得到的商就是能够装满的袋数,所以商的整数部分就是新进制-1位的数码。我们用上一步得到的商的小数部分乘以基数,相当于将那些规格等于新进制的基数的倒数的大袋子里的糖果全部暂时装入规格更小(新进制的-2位的位权,即N-2)的小袋子里,得到的积就是能偶装满小袋子的数量,积的整数部分(如果有)就是新进制-2位的数码。以此类推,直到积的小数部分为0或者达到需要的精度,我们就可以得到新进制小数部分各个数位的数码。
想必以上词不达意、含含糊糊的解释说明属实不容易理解,但如果天资聪慧的你竟然看懂了,那么相信你也同样可以想明白以下几点:
并不是必须要将十进制数拆分成整数部分和小数部分,再分别进行转换,只是这样做最为简便。你可以用十进制数除以其他进制任何一个数位的位权作为转换的第一步,然后同样可以逐步计算出其他进制每个数位的数码。
转换时第一步都要使用除法运算,至于后续是使用除法运算还是乘法运算,取决于接下来要计算高位的数码还是低位的数码,以及第一步除法运算的结果是整数加余数的形式还是整数加小数的形式。计算高位的数码时,总是要使用除法运算的。用余数计算低位的数码时应当除以低位的位权,用小数计算低位的数码时应当乘以基数。这就时为什么我们转换整数部分时要连除基数,而转换小数部分时要连乘基数。
计算得到各数位的数码后,要按照数位由高到低的顺序将数码连接起来。我们在转换整数部分的时候,先算出低位的数码,又算出高位的数码,所以是按照倒序将他们连接起来。我们在转换小数部分的时候,先算出高位的数码,又算出低位的数码,所以是按照正序将他们连接起来。
领取专属 10元无门槛券
私享最新 技术干货