二进制数字编码过程中的计算思维
2021-04-21陈凯
陈凯
在信息技术教学内容中,在讲到将十进制数转换成二进制数字的方法时,常会介绍“除二取余”法,简单来说,就是将某十进制数不停地除以2并得到余数,若把所有余数按生成次序反向列出,即可得到某十进制数字所对应的二进制数。至于为什么采用这样的方法,解释起来却有些麻烦,尽管可以说明这个过程其实是二进制数转十进制数的逆方法,但似乎很多人对逆向过程的领悟力远逊于正向的过程。笔者在研究后,将十进制数转换成二进制数的过程设计成了一个项目活动,试图让学生通过游戏体验和创意设计的过程,理解为什么能用“除二取余”法进行二进制数字编码,并能领会计算思维的方法在解决问题中所发挥的独特作用。
任务一:撕纸游戏
在一张纸条上均匀地画上标记,之间留出一定空白:# # # # # # # # # # # # #。将纸对折,如果折痕经过#号,则将此#号撕下,放在一边,与此同时,纸条被撕成两半,留下一半扔掉另一半;如果折痕经过的是空白处,则将此空白撕下,放在一边,被撕成两半的纸条同样留下一半扔掉另一半。13个#号的操作过程依次如表1所示(表中用下划线表示空白)。将最后结果中的#号看成1,空白看成0,便得到了13所对应的二进制编码的数字1101。
该任务的作用有两点:其一,将“除二取余”的数学运算过程转化成了一系列的操作动作,这样就将一个运算过程以机械化的形式展现出来;其二,揭示出数学上的“除二取余”和另一种过程是等价的:首先判断数字是奇数还是偶数,如是奇数,则取出1后再对其除以2,如是偶数,则取出0后再对其除以2。反复执行此操作,即可实现二进制数字的编码。这种对数据执行某种操作,并且对执行操作后得到的结果数据继续执行该操作的方法,就是一种迭代。等到该任务完成后,学生可以更直观地体会到,一个机械性的重复操作过程是如何用于解决数学问题的,但到目前为止,学生未必能领悟能通过这种方法,将十进制数字转换为二进制编码数字的原因。
任务二:凑数游戏
列出1、2、4、8、16等十进制数字序列(后一个数总是前一个数的两倍),同时列出每个数字对应的二进制数(后一个二进制数字总比前一个数字末尾处多一个0),注意二进制数前,用0补齐位数,列表如下页表2所示。
这样,就可以用凑数的方法来找出特定十进制数所对应的二进制数,如13可以凑成1+2+8,那么只要将1、2和8对应的右侧的二进制数叠加起来,就得到了13的二进制数的编码,相信很多教师都在课堂中讲解过这种方法,这里就不赘述了。但其实可以借助表2来为最终解释二进制数的编码问题提供重要的线索:任意一个偶数,其实都是另一个数字的两倍,在二进制数中,在某数后跟一个0,则得到原数的两倍。任意一个奇数,其实都是另一个数字的两倍加上1,在二进制数中,在某数后跟一个1,则得到原数的两倍加1。相信这些都很容易被理解。
任务三:推理游戏
活动进展到这里,就已经掌握了揭开“除二取余”法之所以有效的原因的所有线索,依靠纯粹的推理就能完成将某十进制数转换成二进制数的过程,仍然用十三(这里用中文来避免烦琐的不同进制数字格式的写法)来举例。
由于十三是奇数,那么在二进制数字中,它一定是某数后跟上1而形成的:(某数)1。
虽然不知道括号里某数的二进制形式是什么,但可以肯定的是,这个数字是十进制数六,因为只有六的两倍加1才是13:(六)1。
这个六显然是偶数,那么在二进制数字中,它一定是另一个某数后跟上0而形成的,这里的另一个某数只可能是三:((三)0)1。
接下去推理过程是类似的,继而得到:
(((一)1)0)1)
然后得到:
((((零)1)1)0)1)
就算是再往下做,也只是得到更多的零而已,所以可以规定,当出现中文的“零”时,则结束推理过程。实际上,人脑所做的推理过程,计算机也一样能做到,对于计算机来说,这种方法叫做递归。到这里就解释了利用“除二取余”得到二进制编码的数字的原因,可以和第一个撕纸游戏遥相呼应起来。同时,这种对数据反复执行操作的方法,也能和后续算法模块中的内容建立起关联,即便不讲递归,也能借助循环嵌套分支结构的程序代码,来实现将十进制数字编码为二进制数字的过程。
任务四:创意设计
人类掌握知识和技能的目的是建设和改造世界,既然学生们已经领悟了将十进制数编码为二进制数字的方法,那么,就充分鼓励大家将自己学习的成果运用到实践中去吧。
相對于掌握“除二取余”法,更具综合性、更能体现自主创造性的任务,是设计出一个系统或装置来实现类似于“除二取余”的功能,大家可能会想,当教学内容讲到二进制编码的时候,学生极有可能尚未学习算法和编程,更遑论迭代和递归了。然而,即便不用程序设计的知识和技能,也一样有办法设计出各种有趣的插电的或不插电的、自动化的或半自动化的系统或装置(考虑到课时和可用器材上的限制,也可以仅仅让学生绘制出某个装置的设计方案),来实现这样的功能,并让学生在设计过程中体会计算思维的作用。当然,为了提高教学效率,教师需要给出一些启发和提示。
下面是笔者设计的难度不一的几个例子,限于篇幅,这里只简单说明这些系统如何实现二进制数字编码的大致思路,这样也给各位读者留下思考的空间。
1.齿轮计数
图1是一个半自动化的简单装置,底下的齿轮有10个短齿和5个长齿,只有长齿可以拨动上部的齿轮。长齿左侧写0,右侧写1。上部齿轮周围均匀列出0到13刻度值,默认指针指向刻度0。该装置工作过程以13为例,用手轻轻拨动下部短齿13次,则上部齿轮指针指向6,同时下部齿轮指向上部齿轮的刻度值为1,记录下6和1,其中6是下一轮操作的拨动次数,而1是二进制编码的一部分。然后用手轻轻拨动下部短齿6次,则上部齿轮指针指向3,同时下部齿轮指向上部齿轮的刻度值为0……以此类推,就能得到13所对应的二进制编码的数字。
2.字符串替换系统
用若干个*号代表数字,用“.”来代表字符串结尾,然后多次利用记事本的“编辑—全部替换”功能,生成该数字所对应的二进制编码,在替换规则中可用到其他字符。为了便于自动化过程的实现,要求对于任何数字,也就是任何数量的*号,“编辑—全部替换”的规则和顺序都是一样的,允许多次批量操作一系列的替换动作。举例说,如设置替换动作为A、B、C、D,则可多次重复进行A、B、C、D操作,但不能在操作过程中临时修改替换规则,也不能多出某一条规则成为A、B、C、D、E或去除掉某一条规则成为A、B、D。
实现任务的方法不是唯一的,如反复执行以下替换规则就可以实现二进制编码:A.将**替换成#;B.将#.替换成#.0;C.将*.替换成.1;D.将#替换成*。
大家可以用13来测试一下,初始字符串是*************.(注意字符串最后的点)。最后得到的字符串是:.1101。
可以看出,以上替换过程其实还是用了“除二取余”的方法,对于任何个数的*号,都可以用完全一样的规则来实现生成二进制编码数的操作,唯一的区别就是批量进行替换操作的次数。如果使用像Notepad++这样带有宏功能的文本编辑器,就更能展现出自动化的替换操作的优势。
3.数字电路系统
图2展示的是一个用“除二取余”法实现半自动化二进制数编码的数字电路装置,可以用Logisim模拟器进行互动的模拟操作。虽然看上去线路有点多,但其实只用到了若干异或门来做奇偶判断,一个计数器来实现除二的操作,两个移位寄存器来实现数据存储,其原理并不复杂。在实际教學中,可由教师给出这个装置,然后让学生通过互动实验,自行摸索出操作方法。
图2中演示了对数字9进行二进制编码的初始阶段,首先,记录右下侧输出(圆形标志)数据为1,然后将“读数和运算切换开关”切换为“01”表示开始运算,连续点时钟信号38次(真正的电路中,时钟信号当然是自动发出的),再将“读数和运算切换开关”切换为“10”表示开始读数,连续点时钟信号2次,记录右下侧输出数据……以上过程反复执行,即可得到数字9所对应的二进制编码的数字。由于点击的数量和顺序都是固定的,所以可以看出这个电子装置具有进一步扩展的能力,如能为其补充一个外围控制电路,便可使之全自动化地实现二进制编码工作。
本文提供的例子,对于如何以培养计算思维的目的设计项目活动给出了一个有启发性的思路:某些问题的解决工具在功能上是受到限制的,该问题的解决是通过重复批量执行某一些规定步骤才得以实现的,而执行过程中的具体步骤,又可以和某机械装置或电子电路装置中的状态变化进行对应,这样,就使得这个项目活动蕴含与计算思维有关的抽象化、形式化、自动化的特征。