Exercises - Decisions and debugging
Module 4: conditional logic, testing, and locating defects
Name:
Student number:
Choose one answer for each multiple-choice question. Answer the open questions with modular pseudocode or flowcharts, and give your test cases as a table of inputs and expected outputs.
M1) Freezer alarm
A cold store keeps frozen food at -18 °C. A sensor in each freezer sends a temperature reading in degrees Celsius every minute. When the sensor fails to measure, it sends None instead of a number. The function freezer_status must return:
"No reading"when the reading isNone;"Alarm"when the reading is above -15.0 °C;"OK"otherwise.
Listing 1 shows the implementation that a programmer submitted.
A technician runs each of the following checks on its own. Which check fails?
assert freezer_status(None) == "No reading"assert freezer_status(-18.0) == "OK"assert freezer_status(0.0) == "Alarm"assert freezer_status(-15.0) == "OK"
M2) Who can be president?
The U.S. Constitution lists three qualifications for the presidency:
- The person must be at least 35 years old.
- The person must be a natural-born citizen1 of the United States.
- The person must have been a resident in the United States for at least 14 years.
In Listing 2, the main function receives a person’s age, citizenship status, and years of residency as parameters. It calls check_eligibility and prints a message based on the Boolean value returned by that function.
is_citizen parameter is True when the person was a U.S. citizen from birth and False otherwise.
In Listing 3, we have several implementations of check_eligibility. Each function should return True only when all three requirements are met and False otherwise.
Which implementation of check_eligibility correctly determines whether a person is eligible to become President based on their age, citizenship status, and years of residency?
check_eligibility for determining whether a person is eligible to become President (Question 2).
M3) Crane wind limits
A construction site limits crane work by the wind speed measured at the top of the crane. Table 1 gives the action for each wind speed w in meters per second.
Wind speed w (m/s) |
Action |
|---|---|
w < 10 |
Normal |
10 ≤ w < 15 |
Caution |
15 ≤ w < 20 |
Stop lifting |
w ≥ 20 |
Secure crane |
An engineer wrote the pseudocode in Listing 4 for the rule.
The engineer traces the pseudocode for every wind speed in a test set and compares each output with Table 1. With which test set do all tests pass, even though the pseudocode is defective?
- {4, 9.9, 12}
- {5, 16}
- {22}
- {9.9, 10, 14.9, 15}
M4) Delivery fee
A web shop charges a delivery fee in euros. Members never pay the standard fee. Other customers pay no standard fee on orders of €50.00 or more, and €4.95 below that. An order with a bulky item, such as a bookcase, costs an extra €15.00 on top of whatever the standard fee is, including when that fee is 0.
Figure 1 shows the rule as a flowchart.
Listing 5 shows 4 implementations of delivery_fee.
delivery_fee (Question 4).
M5) Printing cost
At a university library, print jobs of up to 10 pages are free for everyone. Longer jobs cost €0.05 per page for students and €0.10 per page for staff. A programmer wrote the rule as one conditional expression, shown in Listing 6.
Python groups nested conditional expressions from right to left: A if c1 else B if c2 else C means A if c1 else (B if c2 else C). It evaluates c1 first.
M6) Gym entry gate
A university gym opens its entry gate with a member card. The gate first checks that the card is valid, then that the gym is open, and finally that this month’s fee has been paid. The gym is open from 6:00 until 23:00, so the hour hour of arrival must satisfy 6 ≤ hour < 23. Figure 3 shows the decision.
A tester wants a test set that makes every Yes arrow and every No arrow of the 3 decisions run at least once. Table 2 lists 4 candidate test sets. Each test case is written as (card_valid, has_paid, hour).
| Set | Test cases |
|---|---|
| 1 | (True, True, 10), (False, True, 10), (True, False, 10) |
| 2 | (True, True, 10), (False, False, 3), (True, True, 23), (True, False, 6) |
| 3 | (True, True, 6), (True, True, 22), (True, False, 12), (False, True, 12) |
| 4 | (False, True, 10), (False, False, 3), (True, True, 23), (True, False, 23) |
M7) Call center review
A call center reviews every shift whose average call lasted more than 8 minutes. The average is the total minutes on the phone divided by the number of calls. A shift can have 0 calls, for example during a phone outage, and such a shift is not reviewed.
The function needs_review(calls, total_minutes) must return True when the shift needs a review and False otherwise. It must never stop with an error. Listing 7 shows 4 implementations.
Which implementations in Listing 7 meet the specification for every shift, including a shift with 0 calls?
needs_review (Question 7).
M8) Order status
A web shop shows each order’s status from 2 facts: whether it has been paid, and whether it has been shipped. Table 3 gives the required status for each combination. An order that was shipped without being paid points to a mistake in the warehouse, so staff must check it.
| Paid | Shipped | Status |
|---|---|---|
False |
False |
Awaiting payment |
True |
False |
Packing |
True |
True |
On its way |
False |
True |
Check order |
A programmer wrote the match statement in Listing 8. The pattern _ matches any value.
match statement for the order status (Question 8).
Which statement about Listing 8 is true?
order_status(False, True)returns"Check order", because that case matches the inputs exactly.- The last case can never run, so
assert order_status(False, True) == "Check order"fails. - Python refuses to run the function, because 2 cases match the same inputs.
order_status(True, True)returns"Awaiting payment", because_matches any value.
M9) Surge multiplier
A ride-hailing app raises its prices when riders wait and few drivers are free. The price of a ride is multiplied by a surge multiplier that depends on the number of waiting ride requests and the number of available drivers in an area. Listing 9 gives the rule.
A tester wrote the test cases in Table 4 before anyone implemented the rule. The expected multiplier of each case should follow from the pseudocode.
| Test | Requests | Drivers | Expected multiplier |
|---|---|---|---|
| T1 | 10 | 5 | 2.0 |
| T2 | 0 | 0 | 3.0 |
| T3 | 5 | 5 | 1.5 |
| T4 | 6 | 5 | 1.5 |
M10) Ticket price errors
A museum sells tickets at 3 prices. Children under 12 pay €5.00, visitors aged 65 or over pay €7.50, and everyone else pays €10.00. Three students each wrote a small program for the rule. Listing 10 shows the 3 programs with the output from running each one directly below its code. In Program 2, the user enters 70 at the prompt.
ticket_price(8) is requested; Python rejects the code before it can run.
70; execution stops at the comparison inside ticket_price.
Age: 70
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[3], line 11 7 return 10.0 8 9 10 age_typed = input("Age: ") ---> 11 print(ticket_price(age_typed)) Cell In[3], line 2, in ticket_price(age) 1 def ticket_price(age: int) -> float: ----> 2 if age < 12: 3 return 5.0 4 elif age >= 65: 5 return 7.5 TypeError: '<' not supported between instances of 'str' and 'int'
- A syntax error means Python cannot read the code as valid Python. It is reported before the program starts.
- A runtime error stops a program while it is running. The last line of its traceback names the error Python found.
- A logic error means the program runs but gives a result that breaks the stated rule. Python may report no error, so check the output against the rule.
Which set of changes would make all three programs follow the museum’s rule?
- Add the missing colon in Program 1; change
age: inttoage: strin Program 2; changeage <= 12toage < 12in Program 3. - Add the missing colon in Program 1; pass
int(age_typed)toticket_pricein Program 2; changeage <= 12toage < 12in Program 3. - Add the missing colon in Program 1; pass
int(age_typed)toticket_pricein Program 2; changeage >= 65toage > 65in Program 3. - Add the missing colon in Program 1; pass
int(age_typed)toticket_pricein Program 2; leave Program 3 unchanged because it runs without an error.
M11) Stepping through a call in VS Code
A delivery charge looks wrong, so you pause the program in the VS Code debugger. In Listing 11, Breakpoint A is on the call to delivery_fee, and Breakpoint B is on print(total). Both breakpoints are enabled. Execution is paused at Breakpoint A, before that line runs, so fee does not have a value yet.
You want to inspect distance_km inside delivery_fee, return to order_total, finish the assignment to fee, inspect it on the following line, and then run to Breakpoint B. Which sequence of VS Code debugger controls does that?
- Step Into, Step Out, Step Over, Continue
- Step Into, Step Out, Continue
- Step Over, Step Out, Step Over, Continue
- Step Into, Continue, Step Over, Continue
M12) Line execution order in nested calls
The main function in Listing 12 passes the result of double(3) to add_one. The comments A to E mark lines in the function bodies. Consider only those marked lines when tracing the program.
In what order does Python execute the marked lines, and what does the program print?
- C, D, A, B, E; prints
7 - A, B, C, D, E; prints
8 - C, A, D, B, E; prints
7 - E, C, D, A, B; prints
7
M13) Boxes per pallet
A warehouse scanner sends the number of boxes in a delivery as text, such as "120". The function boxes_per_pallet in Listing 13 converts the text to a whole number and divides the boxes evenly over the pallets. For a valid delivery, the box count is nonnegative, the pallet count is positive, and the box count is divisible by the pallet count. The calls below also test invalid inputs. When the text is not a whole number, the function returns -1 so that a clerk can count the delivery by hand.
You do not need to memorize the error names. int(text) raises a ValueError when the text cannot be converted to an integer. Division or floor division by 0 raises a ZeroDivisionError.
What happens when Listing 13 is run?
- It prints
30,24,-1, and-1. - It prints
30,24, and3, then stops with aZeroDivisionError. - It prints
30,24,3, and-1. - It prints
30,24, and-1, then stops with aZeroDivisionError.
M14) Shipping label traceback
A parcel service charges shipping per kilogram. Parcels within the Netherlands ("NL") cost 120 cents per kilogram, parcels to other EU countries ("EU") cost 250 cents, and all other destinations cost 400 cents. The program in Listing 14, saved as shipping.py, prints the text for a shipping label.
def rate_per_kg(zone: str) -> int:
if zone == "NL":
return 120
elif zone == "EU":
return 250
elif zone == "World":
return 400
def shipping_cost(weight: int, zone: str) -> int:
return weight * rate_per_kg(zone)
def label_text(weight: int, zone: str) -> str:
cost = shipping_cost(weight, zone)
return f"{zone}: {cost} cents"
print(label_text(2, "UK"))Running the program produces the traceback in Listing 15.
Traceback (most recent call last):
File "shipping.py", line 19, in <module>
print(label_text(2, "UK"))
^^^^^^^^^^^^^^^^^^^
File "shipping.py", line 15, in label_text
cost = shipping_cost(weight, zone)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "shipping.py", line 11, in shipping_cost
return weight * rate_per_kg(zone)
~~~~~~~^~~~~~~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'Where is the defect, and why?
- In
rate_per_kg. Its last branch testszone == "World", so any other destination reaches the end of the function, which returnsNone. - On line 11 of
shipping_cost. Python cannot multiply a number by a function call, so the rate must be stored in a variable first. - On line 19.
"UK"is not a valid zone, so the call must pass"World"or"EU"instead. - In
shipping_cost. It must catch theTypeErrorwithtry-exceptand return 0.
Q1) Dispatch an elevator
An office building has two elevators, A and B. Someone presses Up or Down on a floor. The controller chooses which elevator answers the call.
Each elevator has a current floor and a target floor. If these are equal, the elevator is idle. Otherwise, it moves toward its target. Assume that the call and all floors are valid and both elevators are working.
Travel rule. An idle elevator goes straight to the call. A moving elevator can stop for a call on its current route when the call floor is strictly ahead of it, no farther than its target, and the pressed direction matches its movement. It then travels straight to the call. In every other case, it first reaches its target and then travels to the call. Count one floor of travel for each floor crossed. For example, abs(2 - 5) = 3.
Choice rule. The elevator with the shorter travel distance answers. If their distances are equal, A answers.
For example, A is idle on floor 4. B is on floor 9, traveling down to floor 1. Someone on floor 6 presses Down. A travels 2 floors; B stops on its current route after 3 floors. The controller chooses A.
Your task. In pseudocode or flowcharts, design these two procedures:
Travel Distance: given one elevator’s floor and target, the call floor, and the pressed direction, return its travel distance to the call.Choose Elevator: given both elevators and the call, callTravel Distancefor each elevator and returnAorB.
Name each procedure and state its inputs and output. Then complete Table 5. Show both distances and the chosen elevator. An elevator is written as current floor → target floor.
| Case | A | B | Call | Distance A | Distance B | Choice |
|---|---|---|---|---|---|---|
| On the way | 2 → 2 | 7 → 0 | floor 5, Down |
|||
| Moving away | 2 → 2 | 7 → 12 | floor 5, Down |
|||
| Equal distances | 3 → 3 | 9 → 9 | floor 6, Up |
For a moving elevator, compare the call floor with both its current floor and its target. If it cannot stop on the way, add the distance to its target to the distance from that target to the call.
Footnotes
The citizenship requirement concerns when a person became a U.S. citizen. For example, Elon Musk — a South African-born entrepreneur — and Arnold Schwarzenegger — an Austrian-born actor and politician — are both naturalized citizens, so they are not eligible to become President.↩︎