Scratch编程与数学思维融合:从完全数算法到可视化教学实践 1. 项目缘起当数学老师决定“不务正业”作为一名教了十几年数学的老师我常常在思考一个问题如何让学生们真正“看见”数学而不仅仅是“计算”数学。那些课本上冷冰冰的定义、定理和公式比如“完全数”对很多孩子来说就是一个需要背诵的考点——“一个数如果恰好等于它的真因子即除了自身以外的约数之和这个数就叫做完全数”。6、28、496……背下来考试能得分然后呢然后这个概念可能就永远停留在记忆的角落与“有趣”和“有用”绝缘。直到我开始接触Scratch这个想法才有了落地的可能。Scratch的魅力在于它把抽象的思维过程变成了可视化的、可交互的积木块。这不正是连接抽象数学与具象世界的绝佳桥梁吗于是我决定“不务正业”一次用Scratch来上一堂关于“寻找完全数”的数学课。这不仅仅是一个编程项目更是一次数学思维的深度探险。我们不再满足于知道“什么是完全数”我们要亲手“造”出完全数或者至少像探险家一样在数字的海洋里“寻找”它们。这个过程会涉及到因数分解、循环遍历、条件判断等核心的数学与编程思想远比单纯背诵定义要深刻得多。2. 完全数探秘从定义到算法的思维转换在动手敲代码之前我们必须把数学问题清晰地“翻译”成计算机能理解的任务。这是所有“数学编程”项目的核心第一步也是最锻炼逻辑思维的一步。2.1 拆解“完全数”的数学定义首先我们回到定义“一个数如果恰好等于它的真因子之和”。我们以6为例找出真因子6的真因子是哪些即所有能整除6且小于6的正整数。它们是1, 2, 3。求和1 2 3 6。判断相等和6等于原数6。所以对于任意一个待检查的数字N我们的任务流程是步骤A找出所有属于区间 [1, N-1] 的能整除N的数即真因子。步骤B将这些真因子相加得到总和S。步骤C比较S和N。如果S N则N是完全数否则不是。这个流程看似简单但其中隐藏着两个可以优化的关键点也是编程思维与纯数学思维的不同之处。2.2 算法优化为什么搜索到 N/2 就足够了在步骤A中最直观的做法是让计算机从1循环到N-1逐个判断是否为N的因子。但作为一个有经验的探索者我们需要思考有没有更高效的方法答案是肯定的。这里就引入了一个重要的数学观察如果a是N的一个真因子那么必然存在另一个整数b使得a * b N且b也是N的真因子。并且a和b中较小的那个一定小于或等于N的平方根。更保守但更容易理解的一个边界是任何一个大于N/2的正整数都不可能是N的真因子。因为最小的真因子是1其对应的配对因子就是N本身这不是真因子。当因子大于N/2时它与任何大于等于2的整数相乘都会超过N。例如对于N28检查到1428/2即可。因为如果有一个因子是15那么和它配对的因子必须小于2才能让乘积为28这不可能。实际上28的真因子是1, 2, 4, 7, 14。我们在检查到14时已经通过28 / 2 14找到了2和14这对因子通过28 / 4 7找到了4和7这对因子。因此在编程时我们的循环范围可以从[1, N-1]优化为[1, N/2]。对于计算机来说这直接将工作量减半当N很大时效率提升是巨大的。这是我们的第一个优化策略。2.3 算法再优化巧用平方根避免重复累加第二个优化更为精妙。我们继续以28为例。当我们用循环i从1遍历到14时i128 % 1 0找到因子1。同时我们立刻知道28 / 1 28但28不是真因子等于自身所以只累加1。i228 % 2 0找到因子2。同时28 / 2 1414是一个不等于28的真因子所以我们可以一次性累加两个因子2 和 14。i428 % 4 0找到因子4。同时28 / 4 77也是真因子累加4和7。注意当我们检查到i7时7已经被作为28/4的结果累加过了。如果我们不加以区分就会把7再累加一次导致错误。这就是重复累加的问题。如何避免关键在于对称性。因数是成对出现的a和N/a。我们只需要遍历较小的那个因子即a然后同时把这对因子都加入总和但必须小心两个特殊情况避免累加自身当a为1时N/a等于N这不是真因子所以只累加1。避免重复累加完全平方数的根如果N是一个完全平方数比如36当i6时36 / 6 6这时a和N/a是同一个数。我们只能累加一次6而不是两次。最优雅的遍历范围是i从1到N的平方根向下取整。对于每个能整除N的i累加i。如果i不等于1且i不等于N/i则累加N/i。这样我们只需遍历大约sqrt(N)次效率得到了指数级的提升。例如判断496是否是完全数只需要遍历大约22次sqrt(496)≈22.27而不是495次或248次。在Scratch中我们可以使用([sqrt v] of (N))积木来获得平方根并用(floor)取整函数来处理。这是我们将要实现的算法核心思想。3. Scratch实战构建“完全数探测器”理论清晰后我们进入动手环节。在Scratch中我们将创建一个交互式的“完全数探测器”它不仅能判断单个数字还能在一个范围内搜索完全数。3.1 角色与界面设计为了让项目更有趣我们可以设计两个角色“数学精灵”角色负责提问、解释和输出结果。我们可以为它添加一些说话和思考的造型。“数字方块”角色用于可视化展示因数和累加过程。当程序找到一个真因子时可以克隆一个“数字方块”显示该因子并让它移动到“和”的区域动态演示累加过程。界面布局上左侧可以放置输入框和按钮中间是“数学精灵”右侧留出一块区域作为“累加展示区”。我们还需要用变量来存储关键数据目标数字用于存储我们要判断的数字。因子和用于在计算过程中累加真因子。当前除数用于循环中的计数器。搜索结果列表用于存储在一定范围内找到的所有完全数。3.2 核心积木脚本解析判断单个数字我们首先编写判断单个数字是否为完全数的函数在Scratch中通常用“自制积木”来实现。自制积木判断完全数输入目标数字初始化将因子和设为0。将当前除数设为1。可选清空舞台上的所有“数字方块”克隆体。循环查找因子并累加重复执行直到当前除数 ([sqrt v] of (目标数字))的向下取整。在循环内如果(目标数字) mod (当前除数) 0那么mod是取余运算余数为0表示整除将因子和增加当前除数。 // 累加小因子设置配对因子为(目标数字) / (当前除数)。如果当前除数 ≠ 1与当前除数 ≠ 配对因子同时成立那么 // 避免累加1的配对因子自身和重复累加平方根将因子和增加配对因子。可选克隆“数字方块”并让它显示当前除数的值并带有动画效果移动到累加区。如果满足上述条件再克隆一个显示配对因子的方块。将当前除数增加1。判断与输出循环结束后判断因子和是否等于目标数字。如果相等让“数学精灵”说“目标数字是一个完全数它的真因子之和正好等于它自己。”否则让“数学精灵”说“目标数字不是完全数。它的真因子之和是因子和。”注意这里采用了基于平方根的优化算法。在向学生解释时可以先实现遍历到 N/2 的版本更直观。待学生理解后再引入平方根优化作为“性能升级”的挑战这样更有阶梯性。3.3 扩展功能范围搜索与可视化单一判断功能完成后我们可以增加更强大的“范围搜索”功能。自制积木寻找区间内的完全数输入起始数 结束数将搜索结果列表设为空。将当前检查数设为起始数。重复执行直到当前检查数 结束数调用“判断完全数”函数但这里我们只关心结果不需要每次显示动画否则会很慢。我们可以创建一个不包含可视化步骤的“判断完全数快速版”积木。如果当前检查数是完全数则将当前检查数加入到搜索结果列表中。将当前检查数增加1。搜索完成后让“数学精灵”说出“在起始数到结束数之间我找到了搜索结果列表的长度个完全数它们是搜索结果列表。”可视化优化提示在进行范围搜索时如果数字很大动态克隆方块会导致程序极其缓慢甚至卡住。因此在搜索功能中应该使用“快速版”判断函数关闭所有动画和克隆。可视化功能仅用于对单个不太大的数进行教学演示。3.4 交互逻辑整合最后我们为绿旗开始和按钮设置事件当绿旗被点击初始化界面清空所有变量和列表。当“判断单个数字”按钮被点击询问“请输入一个你想判断的正整数”将回答存入目标数字然后调用带有可视化效果的判断完全数积木。当“搜索范围”按钮被点击分别询问“请输入起始数字”和“请输入结束数字”然后调用寻找区间内的完全数积木。4. 教学实施与思维拓展不止于代码项目做出来了但作为数学老师我的工作才完成一半。如何利用这个Scratch项目在课堂上引发更深度的数学思考才是关键。4.1 课堂活动设计猜想与验证我会在课堂上这样组织猜想阶段先不告诉学生完全数的定义。我会说“今天我们来玩一个数字游戏。请你们随便想一个正整数然后找出它所有的‘小帮手’即除了它本身以外的约数把这些‘小帮手’加起来。看看有没有哪个数字它的‘小帮手’们加起来正好等于它自己”让学生们先用纸笔尝试6、8、12、28这几个数。发现规律当有学生发现6和28符合时引出“完全数”的概念。然后提问“你们猜下一个完全数大概会是多少是奇数还是偶数”已知的完全数都是偶数但奇完全数是否存在是数学界未解之谜这是一个绝佳的悬念。工具验证这时再展示我们编好的Scratch程序。让学生输入他们猜想的数字或者用范围搜索功能在1-100、1-500之间寻找。他们会惊讶地发现下一个完全数496居然在500以内而再下一个8128则在万位级。这种“猜想-验证-发现”的过程极大地激发了探究欲。探究优化引导学生思考“计算机在找496的因子时是从1检查到495吗这样是不是太慢了我们能不能帮计算机想个更聪明的办法”由此自然引出“搜索到N/2”和“搜索到平方根”的优化讨论将编程思维和数学思维深度融合。4.2 常见错误与调试指南学生在自己动手实现时肯定会遇到各种问题。这里分享几个典型的“坑”“因子和”忘记清零在判断每个新数字前必须将因子和变量重置为0。否则上一个数的结果会累加到下一个数导致一连串的错误判断。这是一个非常经典的编程错误强调“初始化”的重要性。重复累加因子特别是在实现平方根优化算法时如果处理不好i1和i等于N/i的情况就会导致因子1被加两次或者平方根被加两次。调试时可以让学生用“说”积木在循环里把每次找到的因子和当前的因子和打印出来一步步跟踪。循环边界错误重复直到循环的条件设置反了或者当前除数的递增位置放错了都会导致死循环或者漏检。Scratch的“单步执行”点击积木块功能是调试循环的神器。忽略数字1数字1的真因子之和是0因为它没有小于自身的正因子不等于1所以1不是完全数。这是一个很好的边界条件测试案例。4.3 项目延伸打开更广阔的数学世界这个项目可以作为一个起点延伸出许多有趣的课题“相亲数”或“友好数”如果两个数其中每一个数的真因子之和都等于另一个数那么它们就是一对友好数如220和284。修改我们的程序让它能寻找友好数对。“亏数”与“盈数”真因子之和小于自身的叫亏数大于的叫盈数。让程序不仅能判断完全数还能分类输出亏数和盈数并统计比例。性能大比拼让学生分别实现“遍历到N-1”、“遍历到N/2”和“遍历到平方根”三种算法并用Scratch的计时器功能记录判断一个大数比如几千或几万所需的时间直观感受算法优化带来的效率提升。连接历史与人文介绍完全数在古希腊数学毕达哥拉斯学派中的神秘色彩以及欧几里得-欧拉定理如何将完全数与梅森素数联系起来。这能将数学、编程和历史人文打通。回过头看“跟数学老师学Scratch | 寻找完全数”这个项目其核心价值不在于最终那个能跑的程序而在于整个过程中学生所经历的将一个严谨的数学定义一步步拆解成逻辑步骤计算思维思考如何让步骤更高效算法思维用积木块将其构建出来工程思维并在调试中不断修正自己的理解调试与反思。当学生看到自己编写的程序飞快地验证了他们的猜想或者发现了某个意想不到的数字规律时那种融合了数学之妙与创造之乐的兴奋感正是我们作为教育者最希望点燃的火花。这个项目告诉我最好的学习发生在学生从知识的消费者转变为问题的解决者和工具的创造者之时。