← Course Hub← 课程主页 ← All Units← 返回单元列表
H I G H  S C H O O L  C O M P U T E R  S C I E N C E
Solutions解答

Functions and Modular Design函数与模块化设计

Practice Questions · AP CSP-Feeder · US / ON / BC / AB Styles练习题集 · AP CSP 衔接 · 美 / 安 / 卑 / 阿省风格

EASY MEDIUM HARD 🇺🇸 US 🇨🇦 ON 🇨🇦 BC 🇨🇦 AB AP CSP-style MCQAP CSP 风格选择题 AP CSP-feeder FRQAP CSP 衔接简答题 ON Provincial-style安大略省考风格 BC Provincial-style卑诗省考风格 AB/Universal Applied阿省/通用应用题 Honors荣誉级
🇺🇸 US CSTA / AP CSP美国 CSTA / AP CSP3A-AP-17 · 3A-AP-18 · AAP-3.B
🇨🇦 Ontario安大略ICS3U A3.1 · A3.2 · B2.3
🇨🇦 British Columbia不列颠哥伦比亚CS 11 / CP11: functions, modularity, pre-built librariesCS 11 / CP11:函数、模块化、预建库
🇨🇦 Alberta阿尔伯塔CSE2110: outcomes 3.2, 3.3, 3.3.3, 3.4CSE2110:结果 3.2、3.3、3.3.3、3.4

Full Syllabus Map in Study Guide: ../Study Guides/Unit_4_Functions_and_Modular_Design.html. CS has no AB standalone diploma exam; AB framing uses CSE2110 outcomes.完整大纲对照见学习指南:../Study Guides/Unit_4_Functions_and_Modular_Design.html。CS 无独立 AB 毕业考;AB 题使用 CSE2110 结果框架。



Name:姓名:Date:日期:
PART I  ·  SHORT RESPONSE第一部分  ·  短答题AP CSP-style MCQ + ON/BC short answer · 25 marksAP CSP 风格选择题 + 安/卑省考短答 · 共 25 分

Section A · Short ResponseA 部分 · 短答题

Full solutions below. For MCQs, the correct letter is identified with justification. For short-answer items, complete worked solutions are provided. Code traces show each variable at each step.以下为完整解答。选择题标明正确字母并附说明。短答题提供完整解题过程。代码追踪显示每一步每个变量的值。

Q1 EASY 🇺🇸 US §1 Why Functions?为什么要用函数? [3 marks][3 分]
Answer:答案: (B) The bug must be fixed in all four copies; missing even one creates inconsistency. A1(B) 必须在全部四处修复该错误;漏掉任何一处都会导致不一致。A1

Elimination: (A) is false: repeated code does not slow execution meaningfully. (C) is false: Python has no such restriction. (D) is minor and not the main issue. The correct answer is (B): maintainability. Duplicated code creates N places to fix instead of 1. CSTA 3A-AP-18: "Create artifacts by using procedures within a program." M1 (reasoning) + A1 (correct letter)排除法:(A) 错误:重复代码对执行速度影响微乎其微。(C) 错误:Python 无此限制。(D) 是次要问题,非主要缺点。正确答案是 (B):可维护性。重复代码意味着要修复 N 处而非 1 处。CSTA 3A-AP-18:"通过在程序中使用过程来创建制品。" M1(推理)+ A1(正确字母)

Insight:解题思路: Functions are about maintenance, not just convenience. The DRY principle (Don't Repeat Yourself) says every piece of logic should have a single authoritative location. When a bug is found in duplicated code, there is no guarantee all copies will be updated consistently. That is how silent bugs are born.函数关乎的是可维护性,而不仅仅是方便。DRY 原则(不要重复自己)指出每段逻辑都应该有唯一的权威位置。在重复代码中发现错误时,无法保证所有副本都会被一致更新,这正是隐性错误的诞生方式。
Q2 EASY 🇺🇸 US §2 Defining and Calling Functions定义与调用函数 [3 marks][3 分]
Answer:答案: (C) Hello, Sam! then Hello, Alex! A1(C) Hello, Sam! 然后 Hello, Alex! A1

The function IS called twice (eliminating A). Arguments bind in order: first call binds name = "Sam" printing Hello, Sam!; second call binds name = "Alex" printing Hello, Alex!. (B) is wrong because name is the parameter placeholder; it receives the actual argument. (D) reverses the order. M1 (reasoning) + A1 (correct letter)该函数确实被调用了两次(排除 A)。实参按顺序绑定:第一次调用绑定 name = "Sam",打印 Hello, Sam!;第二次调用绑定 name = "Alex",打印 Hello, Alex!。(B) 错误,因为 name 是形参占位符,它接收实际实参。(D) 颠倒了顺序。M1(推理)+ A1(正确字母)

Insight:解题思路: Defining a function does not run it. Code inside the def block executes only when the function is called. Each call creates a fresh binding of the argument to the parameter name, so the same function can produce different output each time it is called with different arguments.定义函数不会运行它。def 块内的代码只在函数被调用时执行。每次调用都会将实参新鲜地绑定到形参名,因此同一函数每次用不同实参调用时可以产生不同的输出。
Q3 MEDIUM 🇨🇦 ON §3 Parameters and Arguments形参与实参 [5 marks][5 分]
(a) Parameters: base and exponent. [1]形参:baseexponent[1]
(b) Call power(3, 2): base = 3, exponent = 2. Loop runs twice (i = 1, 2). After i=1: result = 1*3 = 3. After i=2: result = 3*3 = 9. Return value = 9. M1 (bindings) + M1 (trace) + A1 (return value) = [3]调用 power(3, 2)base = 3exponent = 2。循环执行两次(i = 1, 2)。i=1 后:result = 1*3 = 3。i=2 后:result = 3*3 = 9。返回值 = 9M1(绑定)+ M1(追踪)+ A1(返回值)= [3]
(c) power(2, 4) = 16; the function multiplies 2 by itself 4 times (2^4 = 16). [1]power(2, 4) = 16;该函数将 2 自乘 4 次(2^4 = 16)。[1]
Insight:解题思路: Parameters (base, exponent) are placeholders in the definition. Arguments (3, 2) are the actual values supplied at the call site. Each call produces fresh, independent copies of the parameters. That is why calling power twice with different arguments gives different results without either call affecting the other.形参(baseexponent)是定义中的占位符。实参(3、2)是调用处提供的实际值。每次调用都会产生形参的全新独立副本,这就是为什么用不同实参两次调用 power 会给出不同结果,而两次调用互不影响。
Q4 MEDIUM 🇨🇦 AB §4 Return Values返回值 [7 marks][7 分]
(a) Call grade(82), so score = 82. Check: 82 >= 90? No. 82 >= 80? Yes. RETURN "B" executes immediately. Return value = "B". M1 (trace IF sequence) + M1 (identify correct RETURN) + A1 (value) = [3]调用 grade(82)score = 82。检查:82 >= 90?否。82 >= 80?是。立即执行 RETURN "B"。返回值 = "B"M1(追踪 IF 序列)+ M1(确定正确的 RETURN)+ A1(值)= [3]
(b) Output 1: B (stored in result, then output). Output 2: F (55 < 60, falls through to last RETURN). [2]输出 1:B(存入 result 后输出)。输出 2:F(55 < 60,落到最后的 RETURN)。[2]
(c) A RETURN statement exits the function immediately; execution returns to the caller, so no code after the executed RETURN runs. [1]RETURN 语句立即退出函数;执行权返回调用方,因此执行的 RETURN 之后的代码都不会运行。[1]
(d) A value-returning function sends a result back to the caller via RETURN, which can be stored or used in an expression. A procedure (void function) performs an action (e.g., prints) but produces no value the caller can capture. [1]有返回值的函数通过 RETURN 将结果传回调用方,该结果可被存储或用于表达式。过程(无返回值函数)执行某个操作(如打印),但不产生调用方可捕获的值。[1]
Insight:解题思路: The early-return pattern (a chain of IF/RETURN statements) is a concise alternative to if/elif/else. Each RETURN acts as a gate: once a condition is true, the function is done. This is why order matters: if the checks were reversed (60 before 90), a score of 95 would incorrectly return "D".提前返回模式(一串 IF/RETURN 语句)是 if/elif/else 的简洁替代方案。每个 RETURN 都充当一个关卡:一旦条件为真,函数就完成了。这就是为什么顺序很重要:如果检查顺序颠倒(60 在 90 之前),分数 95 会错误地返回 "D"。
Q5 MEDIUM 🇨🇦 BC §5 Variable Scope变量作用域 [7 marks][7 分]
(a) Line A: 50. The global variable score = 50 has been set before Line A; the function has not yet been called so it has not been modified. A1 + M1 = [2]第 A 行:50。全局变量 score = 50 已在第 A 行之前设置;函数尚未被调用,因此未被修改。A1 + M1 = [2]
(b) Line B: 60 (the function adds 10 to the global 50, returns 60). Line C: 60 (the global was changed to 60 by the function call). [2]第 B 行:60(函数将全局 50 加 10,返回 60)。第 C 行:60(函数调用已将全局变量改为 60)。[2]
(c) Using a parameter-based design (update(score) returning the new value) makes the function's behaviour depend only on its inputs, not on hidden state. One risk of global state: calling the function twice gives different results each time because the global accumulates changes, breaking reproducibility. M1 + A1 = [2]使用基于参数的设计(update(score) 返回新值)使函数的行为只取决于其输入,而不取决于隐藏状态。全局状态的一个风险:多次调用函数每次给出不同结果,因为全局变量累积变化,破坏了可重现性。M1 + A1 = [2]
(d) No: each function's local variables are completely independent; same name in two different functions refers to two separate storage locations. [1]不会:每个函数的局部变量完全独立;两个不同函数中的同名变量指向两个独立的存储位置。[1]
Insight:解题思路: The key question for scope is: where was the variable created? Global = outside all functions (visible everywhere). Local = inside a function (visible only there, destroyed on return). When a function silently changes a global, it couples its behaviour to program-wide state, which makes debugging and testing much harder.作用域的关键问题是:变量在哪里创建?全局 = 所有函数之外(处处可见)。局部 = 函数内部(只在那里可见,返回时销毁)。当函数悄悄改变全局变量时,它将自身行为与程序范围的状态耦合,这使调试和测试困难得多。
PART II  ·  EXTENDED RESPONSE第二部分  ·  简答题AP CSP-feeder FRQ + Honors · 30 marksAP CSP 衔接简答题 + 荣誉级 · 共 30 分

Section B · Extended ResponseB 部分 · 简答题

Worked solutions below. All traces show variable values at each step. Mark scheme notes are shown in JetBrains Mono. Each solution card ends with an Insight block identifying the key examiner expectation.以下为解题过程。所有追踪均显示每一步的变量值。评分要点以等宽字体标注。每张解答卡以解题思路模块结束,指出考查的核心要点。

Q6 EASY 🇺🇸 US §6 Modular Design模块化设计 [7 marks][7 分]
(a) Procedures (void): get_scores and display_report. Wait: get_scores returns a list, so it IS value-returning. Correction: the two procedures are display_report only has OUTPUT, no RETURN. get_scores has a RETURN. Re-check: get_scores RETURN scores = value-returning. compute_average RETURN = value-returning. letter_grade RETURN = value-returning. display_report = outputs only, no RETURN = procedure. So only display_report is a pure procedure. Accept: display_report (no RETURN); note get_scores also returns. A1 (display_report) + M1 (justification = has OUTPUT but no RETURN) = [2]过程(无返回值):重新检查:get_scores 返回成绩列表(有 RETURN)= 有返回值。compute_average 有 RETURN = 有返回值。letter_grade 有 RETURN = 有返回值。display_report 只有 OUTPUT,无 RETURN = 过程。因此只有 display_report 是纯过程。可接受:display_report(无 RETURN);注意 get_scores 也有返回值。 A1(display_report)+ M1(理由 = 只有 OUTPUT 无 RETURN)= [2]
(b) Scores = [85, 90, 78, 92, 80]. Total = 85 + 90 + 78 + 92 + 80 = 425. Return value = 425 / 5 = 85.0. M1 (sum) + M1 (divide) + A1 (85.0) = [3]成绩 = [85, 90, 78, 92, 80]。合计 = 85 + 90 + 78 + 92 + 80 = 425。返回值 = 425 / 5 = 85.0M1(求和)+ M1(除法)+ A1(85.0)= [3]
(c) Accept any one of: (i) Each function can be tested independently; for example, test compute_average with known values before connecting it to the rest. (ii) If the average formula needs to change, only compute_average needs editing, not the entire program. (iii) The main program reads like a high-level story, hiding complexity in sub-functions. M1 + A1 = [2]接受以下任意一个:(i) 每个函数可以独立测试;例如,在与其余部分连接之前,用已知值测试 compute_average。(ii) 如果平均值公式需要更改,只需编辑 compute_average,而不是整个程序。(iii) 主程序读起来像高层故事,将复杂性隐藏在子函数中。M1 + A1 = [2]
Insight:解题思路: Modular design gives each function one clear job (single-responsibility). The main program becomes a readable list of high-level actions: get, compute, classify, display. This top-down structure means you can test, debug, and modify each layer independently, and the same sub-functions (like letter_grade) can be reused in other programs.模块化设计让每个函数只做一件明确的事(单一职责)。主程序变成了一个可读的高层操作列表:获取、计算、分类、显示。这种自顶向下的结构意味着你可以独立测试、调试和修改每一层,并且相同的子函数(如 letter_grade)可以在其他程序中复用。
Q7 MEDIUM 🇨🇦 ON §2 + §3 Calling Functions + Parameter Passing调用函数 + 参数传递 [8 marks][8 分]
(a) Call add_and_double(3, 7): a = 3, b = 7. Inside: total = 3 + 7 = 10. Then calls double(10): n = 10, returns 10 * 2 = 20. add_and_double returns 20. M1 (bindings) + M1 (total) + A1 (20) = [3]调用 add_and_double(3, 7)a = 3b = 7。内部:total = 3 + 7 = 10。然后调用 double(10)n = 10,返回 10 * 2 = 20add_and_double 返回 20M1(绑定)+ M1(total)+ A1(20)= [3]
(b) Print 1: 20 (x = 20). Print 2: add_and_double(5, 5) = double(10) = 20. [2]打印 1:20(x = 20)。打印 2:add_and_double(5, 5) = double(10) = 20[2]
(c) A function can call another function, so double is reused inside add_and_double without duplicating the multiplication logic. [1]函数可以调用另一个函数,因此 doubleadd_and_double 内部被复用,无需重复乘法逻辑。[1]
(d) With double multiplying by 3: add_and_double(3, 7) = double(10) = 30. add_and_double(5, 5) = double(10) = 30. New outputs: 30 and 30. [2]double 改为乘以 3 后:add_and_double(3, 7) = double(10) = 30。add_and_double(5, 5) = double(10) = 30。新输出:3030[2]
Insight:解题思路: Part (d) is the DRY principle in action: because double's logic lives in one place, changing it once (multiply by 3) automatically updates every caller. If the multiplication had been written inline in both functions, you would need to change it in two places.(d) 部分正是 DRY 原则的实际体现:因为 double 的逻辑只存在于一处,修改一次(乘以 3)会自动更新所有调用方。如果乘法被内联写在两个函数中,就需要在两处进行修改。
Q8 HARD 🇨🇦 BC 🇺🇸 US §4 + §5 Return Values + Scope返回值 + 作用域 [8 marks][8 分]
(a) n = 4. result = 4 * 4 = 16. Return value = 16. M1 + A1 = [2]n = 4result = 4 * 4 = 16。返回值 = 16M1 + A1 = [2]
(b) a = square(4) = 16. b = cube(3) = 3*3*3 = 27. Print 1: 16. Print 2: 27. Print 3: 16 + 27 = 43. A1 + A1 + A1 = [3]a = square(4) = 16。b = cube(3) = 3*3*3 = 27。打印 1:16。打印 2:27。打印 3:16 + 27 = 43A1 + A1 + A1 = [3]
(c) Each function's local variable result is a separate storage location scoped to that function; they are created independently each time the function is called and destroyed when it returns. [1]每个函数的局部变量 result 是作用于该函数的独立存储位置;每次调用函数时独立创建,函数返回时销毁。[1]
(d) Global version of square:
result = 0   # global
def square(n):
    global result
    result = n * n
    return result
This is worse because: if cube also used global result, calling one function would overwrite the value the other stored, causing unpredictable results when the functions are called in sequence. A1 (code) + A1 (reason) = [2]
全局版本的 square:
result = 0   # global
def square(n):
    global result
    result = n * n
    return result
这样更差,因为:如果 cube 也使用 global result,调用一个函数会覆盖另一个函数存储的值,当函数按序调用时会导致不可预期的结果。A1(代码)+ A1(原因)= [2]
Insight:解题思路: Local scope is what allows two functions to both use result as a variable name without conflict. This is one of the core benefits of functions: they create isolated namespaces. Global variables break this isolation, which is why CSE2110 outcome 3.3 specifically asks students to "analyze and determine the type of scope required."局部作用域使得两个函数都能使用 result 作为变量名而不冲突。这是函数的核心优势之一:它们创建了隔离的命名空间。全局变量破坏了这种隔离,这就是为什么 CSE2110 结果 3.3 特别要求学生"分析并确定所需的作用域类型"。
Q9 HARD Honors荣誉级 🇺🇸 US §5 + §6 Scope + Coupling / Cohesion作用域 + 耦合与内聚 [7 marks][7 分]
(a) Program A: total starts at 0. add_item(15): total = 0+15 = 15. add_item(30): total = 15+30 = 45. Print: 45. Program B: t=0. add_item(0,15)=15, t=15. add_item(15,30)=45, t=45. Print: 45. Both output 45. M1 + A1 = [2]程序 A:total 从 0 开始。add_item(15):total = 0+15 = 15。add_item(30):total = 15+30 = 45。打印:45。程序 B:t=0。add_item(0,15)=15,t=15。add_item(15,30)=45,t=45。打印:45。两者均输出 45。M1 + A1 = [2]
(b) Calling add_item(10) after the two existing calls adds to the already-accumulated total = 45, giving 55, not 10. The result depends on hidden state (the current value of the global) which is not visible at the call site, making behaviour hard to predict. M1 + A1 = [2]在两次现有调用之后调用 add_item(10),会在已累积的 total = 45 基础上累加,得到 55,而非 10。结果依赖于隐藏状态(全局变量的当前值),这在调用处不可见,使行为难以预测。M1 + A1 = [2]
(c) Program B has low coupling: add_item does not depend on any external state; all it needs is its two parameters. It also has high cohesion: the function has one clear job (add a price to a running total) with no side effects. Low coupling + high cohesion is the goal of modular design (AB CSE2110 outcome 3.4). M1 + A1 = [2]程序 B 的耦合度低:add_item 不依赖任何外部状态,只需要两个形参。它也有高内聚度:函数只做一件明确的事(将价格加到累计总额),没有副作用。低耦合 + 高内聚是模块化设计的目标(AB CSE2110 结果 3.4)。M1 + A1 = [2]
(d) Accept e.g.: a program-wide language preference (LANGUAGE = "EN") used across many functions is appropriate as a global constant because it is set once at startup and never changes during execution. [1]可接受例如:程序范围的语言偏好(LANGUAGE = "EN")在许多函数中使用,作为全局常量是合适的,因为它在启动时设置一次,在执行期间从不改变。[1]
Insight:解题思路: Coupling measures how much a function depends on things outside itself. Cohesion measures how focused the function's job is. The ideal function is a black box: given the same inputs, it always returns the same output, regardless of the rest of the program. Program B's add_item is a pure function; Program A's is not: it is coupled to global state and produces side effects.耦合度衡量函数对外部事物的依赖程度。内聚度衡量函数职责的专注程度。理想的函数是一个黑盒:给定相同的输入,无论程序其余部分如何,它始终返回相同的输出。程序 B 的 add_item 是一个纯函数;程序 A 的不是:它与全局状态耦合并产生副作用。
PART III  ·  MODELING / APPLIED第三部分  ·  建模与应用Universal / multi-region applied · 25 marks通用/多地区应用题 · 共 25 分

Section C · Modeling and ApplicationsC 部分 · 建模与应用

Full worked solutions below. All function designs show both pseudocode and Python where applicable. Traces list all parameter bindings and return values explicitly.以下为完整解答。所有函数设计在适用时同时展示伪代码和 Python。追踪过程明确列出所有形参绑定和返回值。

Q10 MEDIUM 🇺🇸 US 🇨🇦 ON §1 + §2 + §3 Writing Functions from Scratch从零编写函数 [8 marks][8 分]
(a) Pseudocode:
FUNCTION to_fahrenheit(celsius):
    SET fahrenheit TO celsius * 9 / 5 + 32
    RETURN fahrenheit
END FUNCTION
Award marks for: FUNCTION keyword + parameter name [M1]; correct formula [M1]; RETURN statement [A1]. [3]
伪代码:
FUNCTION to_fahrenheit(celsius):
    SET fahrenheit TO celsius * 9 / 5 + 32
    RETURN fahrenheit
END FUNCTION
评分要点:FUNCTION 关键字 + 形参名 [M1];正确公式 [M1];RETURN 语句 [A1]。[3]
(b) to_fahrenheit(0): celsius=0, fahrenheit = 0*9/5+32 = 32.0. to_fahrenheit(100): celsius=100, fahrenheit = 100*9/5+32 = 180+32 = 212.0. A1 + A1 = [2]to_fahrenheit(0):celsius=0,fahrenheit = 0*9/5+32 = 32.0to_fahrenheit(100):celsius=100,fahrenheit = 100*9/5+32 = 180+32 = 212.0A1 + A1 = [2]
(c) Python:
def to_fahrenheit(celsius):
    fahrenheit = celsius * 9 / 5 + 32
    return fahrenheit
A1 (def + parameter) + A1 (formula + return) = [2]
Python:
def to_fahrenheit(celsius):
    fahrenheit = celsius * 9 / 5 + 32
    return fahrenheit
A1(def + 形参)+ A1(公式 + return)= [2]
(d) The DRY principle says each piece of logic should have a single authoritative location; by placing the formula in a function, any future change to the conversion (e.g., rounding) only needs to be made in one place instead of three. [1]DRY 原则规定每段逻辑应只有一个权威位置;通过将公式放入函数,未来对转换的任何更改(如四舍五入)只需在一处进行,而非三处。[1]
Insight:解题思路: The verification step (b) is not just busywork: 32 F at 0 C and 212 F at 100 C are the two famous checkpoints for the Celsius-to-Fahrenheit formula. Any function you write should be tested against known inputs before trusting it in production. This "verify your function" habit is what the ICS3U A3.1 expectation is testing.验证步骤 (b) 不只是例行公事:0 摄氏度对应 32 华氏度,100 摄氏度对应 212 华氏度,是摄氏到华氏转换公式的两个著名检查点。你编写的任何函数在正式使用前都应该用已知输入进行测试。这个"验证你的函数"习惯正是 ICS3U A3.1 期望所考查的内容。
Q11 MEDIUM 🇨🇦 ON 🇨🇦 BC §6 + §7 Modular Design + Built-in Functions模块化设计 + 内置函数 [9 marks][9 分]
(a) scores = [72, 88, 65, 91, 78]. Min = 65. Max = 91. Sum = 72+88+65+91+78 = 394. Average = 394/5 = 78.8. Output:
Min: 65
Max: 91
Avg: 78.8
A1 (min) + A1 (max) + M1 (sum=394) + A1 (avg=78.8) = [4]
scores = [72, 88, 65, 91, 78]。最小值 = 65。最大值 = 91。总和 = 72+88+65+91+78 = 394。平均值 = 394/5 = 78.8。输出:
Min: 65
Max: 91
Avg: 78.8
A1(min)+ A1(max)+ M1(sum=394)+ A1(avg=78.8)= [4]
(b) CSTA 3B-AP-16 says "Demonstrate code reuse by creating programming solutions using libraries and APIs." Using built-in functions means reusing well-tested, pre-written code rather than re-implementing the same logic manually; this is the library reuse principle. M1 + A1 = [2]CSTA 3B-AP-16 指出"通过使用库和 API 创建编程解决方案来展示代码复用。"使用内置函数意味着复用经过充分测试的预编写代码,而非手动重新实现相同逻辑;这就是库复用原则。M1 + A1 = [2]
(c) Python:
def find_range(data):
    return find_max(data) - find_min(data)
A1 (calls find_max/find_min) + A1 (subtraction, return) = [2]
Python:
def find_range(data):
    return find_max(data) - find_min(data)
A1(调用 find_max/find_min)+ A1(减法,return)= [2]
(d) find_range(scores) = find_max([72,88,65,91,78]) - find_min([72,88,65,91,78]) = 91 - 65 = 26. [1]find_range(scores) = find_max([72,88,65,91,78]) - find_min([72,88,65,91,78]) = 91 - 65 = 26[1]
Insight:解题思路: Part (c) shows function composition: find_range is built on top of find_max and find_min, which are themselves built on top of built-in functions. This layering is the essence of modular design. BC CP11 calls it "pre-built libraries and their documentation": you use existing, tested building blocks rather than starting from scratch every time.(c) 部分展示了函数组合:find_range 构建在 find_maxfind_min 之上,而后者本身又构建在内置函数之上。这种分层正是模块化设计的本质。BC CP11 将其称为"预建库及其文档":你使用现有的、经过测试的构建块,而不是每次从头开始。
Q12 HARD 🇺🇸 US 🇨🇦 ON 🇨🇦 BC All Sections全部章节 · CSTA 3A-AP-17 / ICS3U B2.3 [8 marks][8 分]
(a) bill=120, percent=15, people=4.
compute_tip(120, 15): bill=120, percent=15. Returns 120*15/100 = 18.0. tip=18.0.
compute_total(120, 18.0): bill=120, tip=18.0. Returns 120+18.0 = 138.0. total=138.0.
per_person(138.0, 4): total=138.0, people=4. Returns 138.0/4 = 34.5. share=34.5.
Output: "Each person pays: 34.5". M1 (tip) + M1 (total) + A1 (share=34.5) + A1 (output) = [4]
bill=120,percent=15,people=4。
compute_tip(120, 15):bill=120,percent=15。返回 120*15/100 = 18.0。tip=18.0。
compute_total(120, 18.0):bill=120,tip=18.0。返回 120+18.0 = 138.0。total=138.0。
per_person(138.0, 4):total=138.0,people=4。返回 138.0/4 = 34.5。share=34.5。
输出:"Each person pays: 34.5"。M1(tip)+ M1(total)+ A1(share=34.5)+ A1(输出)= [4]
(b) Pseudocode:
FUNCTION apply_discount(total, discount_pct):
    SET discount TO total * discount_pct / 100
    RETURN total - discount
END FUNCTION
With discount_pct=10: apply_discount(138.0, 10) = 138.0 - 13.8 = 124.2. New share = per_person(124.2, 4) = 31.05. A1 (function) + M1 (124.2) + A1 (31.05) = [3]
伪代码:
FUNCTION apply_discount(total, discount_pct):
    SET discount TO total * discount_pct / 100
    RETURN total - discount
END FUNCTION
discount_pct=10 时:apply_discount(138.0, 10) = 138.0 - 13.8 = 124.2。新人均分摊 = per_person(124.2, 4) = 31.05A1(函数)+ M1(124.2)+ A1(31.05)= [3]
(c) Each function has exactly one responsibility: compute_tip only computes tips, compute_total only adds, per_person only divides. Any function can be modified independently without affecting the others (e.g., change the tip formula without touching the split logic). [1]每个函数只有一个职责:compute_tip 只计算小费,compute_total 只做加法,per_person 只做除法。任何函数都可以独立修改而不影响其他函数(如更改小费公式而不影响分摊逻辑)。[1]
Insight:解题思路: Part (b) shows the extension power of top-down design. Adding the discount required only one new function, inserted between existing ones. No existing function was modified. This is "open for extension, closed for modification" in practice. CSTA 3A-AP-17 asks students to "decompose problems into smaller components." The tip calculator is a textbook example: one problem (compute a bill), three clean sub-problems, each solved independently.(b) 部分展示了自顶向下设计的扩展能力。添加折扣只需要一个新函数,插入现有函数之间,无需修改任何现有函数。这就是实践中的"对扩展开放,对修改关闭"。CSTA 3A-AP-17 要求学生"将问题分解为更小的组件",小费计算器是教科书级别的示例:一个问题(计算账单),三个简洁的子问题,每个独立解决。