- for-end 语句:用于循环次数已知的情形。
- while-end 语句:适用于循环次数未知的情形,根据条件判断是否继续执行循环。
此外,我们介绍了 break 和 continue 的用法,它们可以更加灵活地控制循环过程的执行。 其中 break 语句用于终止执行 for 或 while 循环,这在找到所需结果后立即退出循环的场景非常有用; continue 语句用于跳过循环的当前迭代,然后继续下一次迭代。
在配套的讲解视频中,我们介绍了断点调试功能,它允许程序在特定位置停止执行, 以 便观察程序的状态和变量的值。使用断点调试功能可以帮助我们更好地理解代码、发现错误。
(3)我们编写的程序可能会出现意想不到的错误或异常情况, 因此异常处理非常重要。 try-catch 语句允许我们在程序中捕获和处理异常,而不会导致程序崩溃。
(4)本章最后介绍了几个常用的程序流程控制指令,它们能实现特定的控制需求:
- tic 和 toc:用于测量代码的执行时间,这可以帮助用户评估程序的性能。
- pause:用于暂停程序的运行,可以指定暂停的秒数。
- input:可以让用户输入数据,支持数据表达式输入和文本输入两种模式。
- warning:用于显示警告信息; warning on/off 也能打开/关闭 MATLAB 的警告信息。
- error :用于显示报错信息并终止程序。
4.6 课后习题
基础篇
Q1. 填空题
(1) 在执行循环语句时,如果陷入了死循环,可以按快捷键 Ctrl+C 中断程序的运行; 如果要自动整理代码的缩进、对齐等可以选中代码按快捷键 Ctrl+i 。
(2) if 后面通常接上关系运算符或逻辑运算符,若为 true 则执行 if 后面的语句。如果 你在 if 后面放上了一个矩阵或者向量,这时候只有当这个矩阵或者向量中的元素 满足 全为1 ,才会被当成 true。
(3) 程序可能会面临意想不到的错误或异常情况,如数据输入错误、文件读取问题, 我们可以使用 try-catch 语句捕获和处理异常。
(4) input 函数有两种调用方式,使用 ’s’ 可获取纯文本输入。
(5) 要获取代码的运行时间,我们可以 tic-toc 。
(6) 代码 pause(60) 可以将程序暂停 1 分钟。
(7) 和 if 条件语句配套的剩下三个关键字是 elseif-else-end 。
(8) 和 switch 条件语句配套的剩下三个关键字是 case-otherwise-end 。
(9) 函数 display 可以将文本、数值等输出到 MATLAB 的窗口。
(10)字符向量使用 ’’ 引起来,字符串使用 ”” 引起来;比较两个字符向量或 者字符串是否相等可以使用函数 strcmp 。
(11)如果不希望看到警告信息,那么可以在运行代码之前先运行 warn off 命令。
(12)元胞数组的元素使用 { } 括起来;在 switch-case 语句中,如果 case 后面是元胞数组,那么当 其中的元素全为1 ,则为逻辑值 1。
(13)如果变量 x 等于 eye(3),那么循环语句 for ii = x 中,进行到第二次循环时变量 ii 的值是 0 1 0 。
(14)使用循环得到 N 次模拟结果,并将最终的结果计算平均值来估计期望,这种方法 称为 伯努利大数定律 。
(15) error 函数可用来显示报错信息并终止程序。
(16)考虑存在循环嵌套的场景,如果你的代码中用到了两个 for 循环, 且在内层循环中使用了一个 break,那么这个 break 会导致 中止内层循环 。
(17)使用 warning 函数显示警告信息时,后续的语句 会 (会/不会)继续运行。
(18)如果 MATLAB 版本较低,使用 warning("abc")会报错,应改成 warning(’abc’) 。
Q 2. 下面这段判断正负数的代码有问题吗?如果有问题应该如何修改?
Q 3. 本章 4.2.1 节中有一个思考题,计算当 n 从 1一直取到 100 时, 下面这个表达式的计 算结果:,并将计算结果保存到一个长度为 100 的行向量 S 中(S 中第 i 个元素表示 y(i)的结果)。我们课堂上给出的代码是:
请回答:(1)y = 0;这行代码能否放在循环的外面?不能
(2)能否优化上面的代码,只循环一次就得到 S。
(3)能否使用第三章的知识,不使用循环直接计算 S。
Q 4. 给定一个包含 3 个元素的行向量 a ,使用 if 语句对向量 a 中的元素按照从小到大的顺序排序,并将排序后的向量保存到 sort_a 中。例如原来 a=[3,8,5] ,那么 sort_a=[3,5,8]。(你可以使用循环重复运行你的代码 100 次,每次生成的 a 都是随机的,测试你的代码是否有问题)
Q 5. 本章 4.2.3 节中,有一道判断 n 是否是质数的例题。当时的思路是遍历从 2 到 n-1 的 所有整数,检查它们是否能够整除 n 。如果找到任何一个能够整除 n 的整数,那么 n 就不是 质数;否则, n 就是质数。事实上我们可以缩小循环遍历的范围来提高效率。 一般来说, 只需要检查从 2 到 n 的平方根(如果为小数则需要向上取整)之间的整数,原因是如果 n 有一个大 于 sqrt(n)的因子,那么它必定有一个小于 sqrt(n)的因子。请解决下面两个问题:(1)优化遍 历的范围,对于 n=100000037,比较优化前后的代码的运行时间;(2)自然数2 至 10000 中 的质数有哪些?(注意 2 也是质数,需要单独判断)。
Q 6. 下面这两段代码输出的结果分别是什么?
Q 7. 一个五位正整数各位数字的五次方和等于该数本身则称该数为五角星数,请找出所 有的五角星数并将其保存到向量 S 中。
Q 8. 生成一个 8 行 5 列的矩阵,矩阵中每一个元素都是在区间[1,10]上取值的随机整数。 接下来请循环每一行,若发现同一行的五个元素中各不相同,则保留该行。
Q 9. 在本章介绍 break 和 continue 的小节中, 有一道和斗地主相关的例题。请使用蒙特卡 罗模拟计算你作为农民首次出现炸弹所需的轮数的期望值。
Q 10. a和b是用户输入的两个常数,如果用户输入“乘法”这个文本,则输出a× b;若 用户输入“除法”这个文本,则先判断 b 是否为 0,若为 0 则生成错误信息:分母不能为 0, 否则输出a/b;如果输入的是其他的文本,则生成警告信息:只能输入乘法或除法。
提高篇
Q 1. 一张 100 元的人民币要换成 10 元、 5 元和 1 元面值的零钱,要求三种面值的零钱的 总张数为 20 张,且三种面值至少都有一张,用一个矩阵表示所有可能的组合,矩阵中每一行 的三个元素分别表示三种面值人民币的张数(例如 8 2 10 三个元素就是矩阵的某一行)。
Q 2. 假设自然界中有一种动物, 它每天被天敌捕食的概率均为 0.02,且每天是否被天敌 捕食这个事件是独立的。请使用蒙特卡罗模拟得到这种动物能存活的天数的期望值。
Q 3. 一个班上有 30 名同学,请使用蒙特卡罗模拟计算至少有两人是同一天生日的概率。
Q 4. 每隔 0.2 秒在屏幕上随机输出 0 或者 1 ,当连续出现三次 1 时, 停止输出。
Q 5. 扔一枚正常的硬币,若要扔出连续的 3 个正面,所需扔硬币的期望次数是多少?请 使用蒙特卡罗模拟进行计算, 精确的数学答案是 14。
Q 6. 有三个长度均为 10 的向量,分别是 r = [5 3 2 2 4 1 3 5 1 4] 、c = [3 4 1 2 5 5 2 4 4 2 ] 、 x = [9 6 3 7 5 1 4 9 2 4],若 A 矩阵是一个元素全为 0 的 5 阶方阵。请根据 r 、c 和 x 三个向量 给 A 矩阵重新赋值:将 x(i)赋值给 A 中第 r(i)行、第 c(i)列的元素(i=1,2, ⋯ ,10)。另外,大家 可以思考能否不使用循环语句得到 A 矩阵?最终得到的 A 矩阵供大家参考:
Q 7. 随机生成一个各行各列的和均为 1 的 5 阶方阵,且该方阵的元素仅为 0 或 1 。例如下 面这个矩阵就符合要求。(大家也可以尝试不使用循环语句得到这个随机的方阵)
Q 8. 将一根长度为 1 米的木棍随机的折成三段, 请用蒙特卡洛模拟分别计算以下两个概 率:(1)每段长度都不大于 0.45 的概率;(2)这三段能构成一个三角形的概率。
Q 9. 一只蜗牛从 10 米深的井底往上爬, 它白天爬 1 米,晚上下落 x 米,其中 x 为[0,2]米 的均匀分布的随机数, 求它爬出这口井的期望天数? 本题选自知乎, 精确答案约为 277 天。
Q 10. 给定一个 1 到 1 亿之间的整数, 请判断这个整数是否为回文数(反向排列与原来一 样的数就叫做回文数。如: 1 、353 、4774 都是回文数)。
Q 11. 二分搜索法不仅可以用于求函数的零点,还可以用于寻找向量中的特定值。给定一 个长度为 100 且递增排列的向量 x 和一个要查找的目标值 t ,使用二分搜索法确定向量 x 中是 否存在目标值 t 。请回答下面两个问题:(1)为了方便,你可以使用下面两句代码随机生成 x 和 t :x = sort(randi(200,1,100)); t = 88; 若 x 中存在多个 t ,你只需要返回任意一个 t 的下标, 如果不存在 t 请返回 0。(2)假设我们令 x = sort(randi(30,1,100)); t = 8,那么 x 中出现多个 t 的次数将大大增加。请在上一问代码的基础上进行调整,使得代码能够输出 t 所在的所有下 标,如果找不到 t 请返回空向量[ ] 。(你可以和 find 函数找到的结果进行比较: find(x == t) , 看看结果是否一致)
Q 12. 有一个人从原点(第 0 格)开始扔一个六面骰子(骰子数值为 1-6),扔到几就向前 走几格, 假设他可以无限次扔骰子,问他恰好走过第 100 格的概率是多少? 这个题目选自知 乎,精确答案约为 2/7。
Q 13. 编写一个猜数游戏的代码,规则如下: 在区间[1,100]上随机生成一个整数 p,用户 需要去猜这个 p 是多少。用户每猜一次程序都会做出相应的提示“请输入你猜的数字:”。若 用户输入所猜的数字小于 p,则提示“你猜小了!”;若大于 p,则提示“你猜大了!”;若相等, 则提示“恭喜你赢了!”,游戏结束。用户猜的次数不能超过六次, 否则提示“最多猜六次,
你失败了。”,此时游戏结束。
Q 14. 知乎上有这样一个问题:
请使用蒙特卡罗模拟验证这个答案是否可行(假设有 30 个人玩这个游戏)。
Q15. 下面这题来自 2022 年阿里巴巴全球数学竞赛,请大家求解该题。
挑战篇
Q 1. 排序算法是一类经典的算法,它们能将一个无序的向量变成有序的向量。请大家在 网上搜索插入排序、选择排序和冒泡排序的讲解视频或者文字资料,并使用 MATLAB 复现这 三种算法。为了测试方便,你可以令 x=randi(100,1,20),将 x 中的元素按照从小到大进行排序。 若你的代码返回的结果和 sort(x)的结果相同,则说明你做对了。(如果你看懂了算法原理也写 不出来代码的话,可以参考本章最后一页的附录,里面提供了这三种算法的伪代码)
Q 2. 在 MATLAB 中, 'parfor'(Parallel for)是一种并行编程工具,它允许在多个处理核心 上同时执行循环迭代。这种方法与常规的 for 循环类似,但能够在多个工作进程上并行执行 循环迭代,从而加快代码运行速度。这对于需要进行重复计算或处理大型数据集的任务尤为 有效。请在 MATLAB 官方网站上搜索关于'parfor'的相关信息,并尝试将之前代码中的 for 循 环替换为 parfor 循环。测试代码是否能够正常运行,并比较 for 循环和 parfor 循环的执行时间。
Q 3. 某游戏中有一把武器,该武器的初始等级为 1 级,在游戏开始时玩家可以免费领取。 在游戏中, 玩家可以花费金币对该武器进行升级,每次升级需要花费 10000 金币,且该武器 最多能被升至 5 级。各等级升级的成功率如下表所示:
等级 | 1 级 | 2 级 | 3 级 | 4 级 | 5 级 |
1 | 65% | 20% | 10% | 5% | 0% |
2 | 25% | 40% | 20% | 10% | 5% |
3 | 10% | 20% | 40% | 20% | 10% |
4 | 0% | 10% | 30% | 40% | 20% |
以等级 1 和等级 3 所在的行为例,表格中各元素的解释如下:
- 1 级武器升级时,有 20%的概率升到 2 级, 10%概率升到 3 级, 5%的概率升到 4 级, 65%的概率不变。
- 3 级武器升级时, 10%概率跌到 1 级, 20%概率跌到 2 级, 20%概率升到 4 级, 10% 概率升到 5 级, 40%的概率不变。
请使用蒙特卡罗模拟,计算打造一把 5 级的武器平均需要花费多少金币(答案约 16 万)。
Q 4.在一台设备上,安装有四只型号和规格完全相同的电子管。假设这些电子管的寿命是 整数小时,且在 1000 至 2000 小时之间均匀分布。设备运行中若出现电子管损坏,有两种维 修方案可供选择:(1)逐个更换方案: 每次只更换损坏的那一只电子管,更换单个电子管需 要 1 小时的时间;(2)集体更换方案:当任意一只电子管损坏时,同时更换所有四只电子管, 一次性更换四只电子管需要 2 小时的时间。已知每只电子管的价格为 100 元,且不论采用哪 种维修方案,设备在更换电子管期间都需要暂停运转,导致的损失为每小时 200 元。请使用 蒙特卡罗模拟判断选择哪一种维修方案更省钱(你可以设置总的模拟时长为 10 万小时,比较 该设备运行 10 万小时后,哪种方案花费更小。参考答案:方案二比方案一节省约 1.3 万)
Q 5. 三门问题(Monty Hall problem)又称蒙提霍尔问题或蒙提霍尔悖论, 它是一道非常 有趣的概率问题, 该问题的答案违反大家的直觉。请大家搜索三门问题的相关资料,并使用 MATLAB 验证三门问题的答案(更换门的概率更高为 2/3)。
Q 6. 莱斯利矩阵是英国生态学家 Leslie 于 1945 年提出的一种数学方法,该方法能利用某 一初始时刻种群的年龄结构现状,动态地预测种群年龄结构及数量随时间的演变过程。请大
家查阅相关资料学习该模型的建模过程,并解决下面这个问题。
已知某动物最长寿命为 10 岁,且初始状态下该动物各年龄组的数据如下表所示:
年龄 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
数量 (万) | 67 | 61 | 60 | 58 | 54 | 52 | 37 | 33 | 28 | 16 | 6 |
雌性生育率 (%) | 0 | 0 | 0 | 23.4 | 40.9 | 61.8 | 39.8 | 19.7 | 10.2 | 0 | 0 |
死亡率 (%) | 9.5 | 3.2 | 3.7 | 3.2 | 3.9 | 4.8 | 6.3 | 15.6 | 26.2 | 31.5 | 100 |
表中雌性生育率解释为雌性个体在一个繁殖周期内平均产生的后代数量(包括雄性和雌 性)。假设该动物繁衍过程满足以下条件: 1. 该动物在各个年龄段的雌雄比例都是 2:1;2. 新 出生注意的该动物的雌雄比例也是 2:1;3. 各年龄组内该动物的生育率和死亡率不随时间变化。
请回答以下问题: (1)预测该动物未来 30 年各年龄段的数量以及占比(参考答案: 30 年后 0 岁数量为 687846);(2)若该动物的天敌在第 30 年后开始出现,这将导致从下一年开 始各年龄段的死亡率均增加到原来的三倍,雌性生育率也降低到原来的一半。请问该动物从 遭遇天敌开始,需要多少年该动物的数量会下降到 1000 只内。(参考答案: 42 年)
Q 7. 本题节选自 2023 年阿里巴巴全球数学竞赛,题目如下: A 与 B 二人进行“抽鬼牌” 游戏。游戏开始时, A 手上有 n 张两两不同的牌。 B 手上有 n+1 张牌,其中 n 张牌与 A 手中 的牌相同,另一张为“鬼牌”,鬼牌与其他所有的牌都不同。游戏规则为:
(1) 双方交替从对方手中抽取一张牌, A 先从 B 手中抽取。
(2) 若某位玩家抽到对方的牌与自己手中的某张牌一致,则将两张牌丢弃。 (3) 最后剩一张牌(鬼牌)时,持有鬼牌的玩家为输家。
假设每一次抽牌从对方手上抽到任一张牌的概率都相同,请用蒙特卡罗模拟 n 分别为 31 和 32 时, A 获胜的概率。(参考答案: n=31 时为 17/33 ,n=32 时为 9/17)。
Q 8. 这是一道排队论的题目。假设某银行工作时间内只有一个服务窗口,工作人员只能 逐个接待客户。当来的客户较多时, 一部分客户就需要排队等待。若假设以下四个条件成立: (1)从银行开始营业起,客户到达的间隔时长(单位为分钟)服从参数,等于 0.1 的指数分布; (2)每位客户的服务时长服从均值为 10,方差为 4 的正态分布(单位为分钟,若服务时长小 于 1 分钟,则按 1 分钟计算);(3)排队按先到先服务的规则,且不限制队伍的长度;(4)银 行每天工作时长为 8 小时,若客户开始服务的时间比银行下班的时间晚,银行不提供服务。
模拟 100 个工作日,计算银行平均每天服务的客户人数以及客户的平均等待时长。
Q 9. 在上一题的基础上,解决以下三个进阶的问题:
(1)由于客户反馈排队等待时间过长,银行决定开设一个新的服务窗口。请计算在有两 个服务窗口的情况下,这 100 个工作日内银行平均每天服务客户的人数以及客户的平均等待 时长。为了简化模拟过程, 假设银行采取先到先服务的策略,只要有窗口空闲,就给先来排 队的客户提供服务(类似于先取号再叫号的策略)。(2)假设银行新设立的第二个窗口每天仅 在前四个小时提供服务(如果客户在后四小时到达银行,则只能去第一个窗口),请重新计算 上述问题。(3)请将第 1 小问的两个窗口推广至 p(p≥3)个窗口,并求解相同的问题。
练习题的讲解视频: https://www.bilibili.com/video/BV1Bw411s7Zb (b 站搜索:MATLAB 课程第 4 章课后习题讲解——数学建模清风老师)
附录: 三种排序算法的伪代码
伪代码(Pseudocode)是一种描述算法的语言,它介于自然语言和编程语言之间。使用 伪代码的目的是使被描述的算法可以容易地以任何一种编程语言(C 、Java 、Python 等)实现, 因此伪代码必须结构清晰、可读性好。
下面给出了挑战篇 Q 1 中三种排序算法的伪代码。为了帮助大家理解,我在伪代码中加 上了注释。另外, 下面给出的伪代码中的循环、判断语句没有以 end 结尾, 大家需要自己根 据代码的缩进来判断 end 的位置。