引子: 为什么十进制转二进制的“辗转相除记录余数倒序输出”的算法是正确的?这个问题陪伴了Formiko半年。
实践:
实践一:把十进制数100转换成二进制数的图
上图和和下图唯一的区别在最后一位上,只是除到0和除到1的区别,但在算法本身的理解上应该不会有本质的区别。
实践二: 十进制数100或许太大,不便于一目了然的验证。试一试十进制数1,2,3。
思考:
以上算法的思路是“对原数反复进行除法得到余数,最后将余数倒序输出”。但是看到如图对十进制数100,1,2,3的操作,都看不出原思路的由来。那我们从这个思路可以推导出几个定论。我们看到在最后倒序输出的时候,最后一个输出的数就是对原数进行第一次除法操作得到的余数。比如有人问我们:“十进制数100的二进制数的个位是多少”,我们肯定会回答:“是0。”得出这个答案的方法有很多,第一种方法是:“十进制数100的二进制是个偶数,二进制偶数的个位是0。”,第二种方法是:“对十进制数100进行一次除法得到余数0,二进制的个位是0。”第二种方法源于我们对“十进制转换二进制算法”的推导。理解这个推导是很容易的。因为二进制数转换成十进制数的方法是:“将二进制数从低位到高位乘2的n次方,将各个结果相加得到十进制数,具体来说二进制数1100100=十进制数0*20+0*21+1*22+0*23+0*24+1*25+1*26=十进制数100。”从中可以看到,将二进制数乘开的过程中,除了个位,其他位的数都乘了2n,也即将非各位结果相加得到的数必定是偶数。所以对任意一个十进制数除2,余数就是二进制数的个位。
我们来做几个小验证。100-->0, 1-->1, 0-->0, 31-->1。
但是这还不够,我们已经得到了计算个位的方法,但是这还不够。我们又想,二进制数的“十位”该怎么求得呢?假如有人问我们:“十进制数14的二进制数的后两位是多少?”或许我们会明白很多。这个问题等同于:“十进制数14的二进制数的“十位”和个位是多少?”。我们还是看前一个问题吧,后两位,不难想到对14除以4,得到的余数便是十进制2,即二进制10,所以十进制数14的二进制的后两位是10。这样对吗,把二进制数乘开就明白了。
所以得到二进制数的“十位”的方法是对原数除2得到第一个余数,对原数除4得到第二个余数,第二个余数减第一个余数等于“十位”。而原算法神奇地避免了除2,除4,除8的操作,而是利用的前一次除法的商,也神奇地避免了减去低位余数的操作,也是直接利用前一次除法的商。
到此,我们用一种方式了解了整数十进制转换二进制的原理。
总结:
思考整数十进制转换二进制原理的一种方法就是从简单到一般,从一位到多位,从低位到高位。
题后话:
Formiko不能自己证明以上思路的最优性,请阅读这篇博文的朋友在评论中批评指正,谢谢。