Cameroon GCE O-Level Computer Science study materials
Cameroon GCE O-Level Computer Science study resources

The Sales-Average Program That Was Right by Luck

Cameroon GCE O-Level Computer Science · Put your knowledge to work in context.

All case studies

The Sales-Average Program That Was Right by Luck

A small business centre in Bamenda keeps daily sales in a plain text file, SALES.TXT, with one whole amount in francs on each line and no header. The manager wants a program that prints the number of days recorded, the average daily sale, and how many days exceeded 50,000 FCFA. An intern produced this pseudocode:

total = 0 count = 0 above = 0 WHILE NOT EOF(SALES.TXT) READ amount total = total + amount count = count + 1 ENDWHILE average = total / count IF amount > 50000 THEN above = above + 1 ENDIF PRINT count, average, above

On a test file containing 60000, 40000 and 80000 the program printed 3, 60000, 1. The manager says the '1' is right by luck and wants the logic corrected before the file is used with 300 days of data, some of which may contain blank lines.

1. Trace the pseudocode with the values 60000, 40000 and 80000, state exactly what is printed, and explain why the 'above' result is unreliable.

Read the worked answer

Trace:

Pass amount read total count
1 60000 60000 1
2 40000 100000 2
3 80000 180000 3

After the third pass the end of file is reached, so the loop exits. average = 180000 / 3 = 60000. The IF statement then executes once, after the loop, using the last value held in amount, which is 80000. 80000 > 50000, so above becomes 1. Output: 3, 60000, 1.

Why it is unreliable: the count is not made per record. It reflects only whichever value happened to be read last. If the file ended with 40000 instead, the output would be 3, 60000, 0 - although two days (60000 and 80000) exceeded the threshold. In a 300-day file the answer would almost never be correct. The test data hid the bug because the last value happened to be above 50,000.

Lesson: a correct-looking single test is not evidence of correct logic. Boundary and ordering tests (last value below the threshold, all values below, empty file) are needed.

2. Identify all the logic and robustness errors and rewrite the corrected pseudocode, including handling of blank lines and an empty file.

Read the worked answer

Errors:

  1. The threshold test is outside the loop, so it uses only the final amount.
  2. There is no guard against count = 0: an empty file causes division by zero.
  3. A blank line cannot be converted to a number; depending on the language it becomes 0 (wrongly lowering the average and day count) or crashes the program.
  4. A trailing blank line can make the loop appear to read a phantom record; EOF must be tested in a way that does not process an empty read as data.
  5. There is no validation that an amount is numeric and non-negative.

Corrected pseudocode:

count = 0
total = 0
above = 0
OPEN SALES.TXT FOR READ
WHILE NOT EOF(SALES.TXT)
   READ line
   IF line is not blank THEN
      IF line is numeric THEN
         amount = VALUE(line)
         IF amount >= 0 THEN
            total = total + amount
            count = count + 1
            IF amount > 50000 THEN
               above = above + 1
            ENDIF
         ENDIF
      ENDIF
   ENDIF
ENDWHILE
CLOSE SALES.TXT
IF count > 0 THEN
   average = total / count
   PRINT count, average, above
ELSE
   PRINT "No valid sales records"
ENDIF

Checks: the IF is now inside the loop, so every record is tested; the count is incremented only for valid records; the empty-file case is handled before division; blank and non-numeric lines are skipped. Note that 'exceeded 50,000' means strictly greater than, so 50000 itself is not counted.

3. The manager now wants the average printed to two decimal places. Explain the change required and the risk if `total` and `count` are declared as integers in a compiled language.

Read the worked answer

Change required: average must be a real (floating-point) variable, and the division must be real division followed by formatting to two decimal places, for example PRINT count, ROUND(average, 2), above or a format string such as %.2f.

The integer-division risk: in many compiled languages, if both operands are integers the / operator performs integer division and discards the remainder. With total = 180001 and count = 3, 180001 / 3 yields 60000, not 60000.33. The decimal part is lost before it ever reaches the print statement, so adding a format to the output does not recover it. The fix is to convert at least one operand to a real, e.g. average = REAL(total) / count, or to declare average as REAL and let the expression be promoted.

Second risk - rounding: printing a real to two places rounds the binary representation, and values exactly halfway (such as 60000.005) may round unexpectedly. For money, some systems keep amounts in whole francs and only format at display time, which avoids accumulating rounding error over 300 days.

Test cases to add: a file whose total is not divisible by the count (e.g. 100, 100, 101), a single-record file, an empty file, and a file with a blank line in the middle. These expose division truncation and the count guard far better than the original three-value test.