Validation, Verification and Testing: Question 4

Syllabus 7.6, 7.7, 7.8, 7.9

Structured 8 marks

A café's loyalty till records how much each customer spends during a morning shift. The pseudocode below reads a sequence of Spend amounts, one at a time, and stops as soon as −1 is entered. It then works out and outputs the average spend per transaction.

01 DECLARE Spend : REAL
02 DECLARE Total : REAL
03 DECLARE Count : INTEGER
04 Total ← 0
05 Count ← 0
06 INPUT Spend
07 WHILE Spend <> -1
08     Total ← Total + Spend
09     Count ← Count + 1
10     INPUT Spend
11 ENDWHILE
12 Average ← Total / Count
13 OUTPUT Average

(a) The algorithm is run once, using this input data, entered in the order shown: 10.50, 9.00, 16.50, −1. Complete a trace table showing the values of Spend, Total and Count, and state the value that is output. [4]

(b) State what happens when the algorithm is run with −1 as the very first value entered, and explain how the pseudocode could be changed to prevent this problem. [3]

(c) Explain why −1, rather than 0, is a sensible sentinel value to mark the end of the input data for this algorithm. [1]

Show worked solution Hide worked solution

Worked solution

Part (a): Tracing the WHILE loop

Total and Count both start at 0 (lines 04-05). The first value is read before the loop (line 06), and every further value is read at the end of the loop body (line 10), so each pass processes one Spend value and then reads the next.

SpendTotalCount
10.5010.501
9.0019.502
16.5036.003
−136.003

When Spend becomes −1, the condition on line 07 (Spend <> -1) is false, so the loop ends immediately. Lines 08-10 do not run again for this value, which is why Total and Count stay at 36.00 and 3 on the last row.

After the loop, line 12 calculates Average ← Total / Count = 36.00 / 3 = 12.00, and line 13 outputs this value.

[4 marks]: [1] for a correct Total column, [1] for a correct Count column, [1] for correctly leaving both unchanged on the row where Spend = −1, [1] for the correct output, 12.00.

Part (b): The division-by-zero bug

If −1 is the very first value entered, the WHILE condition on line 07 is false straight away, so the loop body never runs even once. Total remains 0 and Count remains 0. Line 12 then tries to calculate 0 / 0. A division by zero, which either crashes the program or produces an undefined/meaningless result, instead of sensibly reporting that there were no transactions.

To fix this, the pseudocode should check Count before dividing, for example:

12 IF Count > 0
13     THEN
14         Average ← Total / Count
15         OUTPUT Average
16     ELSE
17         OUTPUT "No transactions recorded"
18 ENDIF

[3 marks]: [1] for identifying that Count (and Total) remain 0, [1] for identifying that this causes a division by zero on line 12, [1] for a workable correction, such as testing Count > 0 before dividing.

Part (c): Why −1 makes a sensible sentinel

A real transaction can have a Spend of exactly $0. For instance, a customer redeeming loyalty points for a free item, so 0 is a valid piece of data that the algorithm must still add to Total and count. Because a negative amount is never possible for a genuine till transaction, −1 can safely be used to signal “no more data”, since it can never be confused with a real Spend value. Using 0 as the sentinel instead would wrongly end the loop the first time a customer spent nothing. [1 mark] for this reasoning.

Final answers

  • (a) Total: 10.50, 19.50, 36.00, 36.00; Count: 1, 2, 3, 3; output = 12.00.
  • (b) −1 first causes 0 ÷ 0 (division by zero); fix by testing Count > 0 before dividing.
  • (c) 0 is a valid Spend value (e.g. a loyalty-points purchase); a negative amount never is, so −1 cannot be confused with real data.