Skip to content

Practice problem

Lowest Reading Of The Day

Easy

Solve in Python or JavaScript · graded against 2 sample tests and a hidden test set in your browser · Published

The Bug Report

The program reads one line of sensor readings and prints the smallest one. It runs, it never raises an error, and on most inputs the answer is right. On inputs that contain a 0 it is unreliable, and not in a way that always looks the same.

Input that shows the problem

Input
4 0 9 2

What the program prints

Output
2

What it should print

Output
0

The 0 in second place is plainly the smallest reading, and the program reports 2 — the value that happens to be last in the list. Swapping the input around to 5 0 gives the right answer, while 0 5 gives 5. Whether the answer is correct seems to depend on where the 0 sits, which is the sort of detail worth following.

Input Format

The input is exactly one line: the readings, as integers from 0 to 1,000,000 separated by single spaces. There is at least one reading.

Output Format

Print one line containing a single integer: the smallest reading in the list.

How to Debug It

The report already hands you a pattern — the answer depends on where the 0 is — so start by making that pattern as small and as sharp as possible. Two readings is enough. Run 0 5 and then 5 0 and write both results down. One of them is right and one is wrong, from the same two values. A bug whose behaviour flips with the order of the input is almost always in the loop's decision, not in how the input is read.

Next, make the state visible instead of imagining it. Print smallest at the top of each pass, and print which branch the condition took, then run the failing four-reading input. Reading down that trace, look for the moment the value stops being the smallest seen so far and starts tracking whatever the current reading is. You are looking for the first line of the trace where the loop overwrites a good answer.

That moment tells you what value smallest was holding when the condition misbehaved, and that is your hypothesis: one specific value of smallest makes the condition say yes when it should say no. State it out loud, then check it by asking what the first half of the condition actually evaluates to for that value — in a shell, in the playground, anywhere. Change one thing: how the condition asks "have I seen a reading yet?" Re-run both two-reading inputs, the failing sample, and then the second sample, which was passing before and must still pass after.

What Was Wrong

The condition was if not smallest or reading < smallest: in Python, and if (!smallest || reading < smallest) in JavaScript. The intent is clear and the shape is common: smallest starts as a sentinel (None / null) meaning "nothing recorded yet", and that first test is supposed to catch the very first reading, before any comparison is possible.

The trouble is that it does not test for the sentinel. It tests whether smallest is falsy, and the sentinel is not the only falsy value a reading can produce. 0 is falsy too — in both languages. So as soon as a 0 becomes the smallest reading, every later reading sees not smallest (or !smallest) as true and overwrites the answer, no comparison needed. The loop stops tracking a minimum and starts tracking whatever it saw last. That is why 4 0 9 2 reports 2: the 0 was found correctly, then discarded by the next reading, then by the next.

The fix is to ask the question the code meant to ask, which is about the sentinel specifically:

Python
if smallest is None or reading < smallest:
JavaScript
if (smallest === null || reading < smallest) {

is None and === null are true for the sentinel and for nothing else, so a legitimate reading of 0 stays put once it wins. Note that JavaScript's loose != would reintroduce a smaller version of the same problem, since null == undefined is true; strict === against the exact sentinel you chose is the version that keeps meaning what you wrote.

Common Mistakes

  • Starting the accumulator at 0 instead of a sentinel. It removes the falsy-zero trap but replaces it with a worse one: 0 is now the answer to beat, so any list of positive readings reports 0, a value that never appeared in the input. A sentinel that cannot collide with real data, or seeding from the first element, is what makes the first comparison honest.
  • Keeping the truthiness test and special-casing 0 alongside it. Two conditions that have to agree about what "nothing yet" means is one more thing to keep in step, and it still fails the day the readings are allowed to be negative or empty strings. One explicit sentinel test covers every case at once.
  • Assuming this only matters for 0. Falsy is a longer list than most people hold in their heads: in Python that includes 0, 0.0, "", [] and {}; in JavaScript 0, -0, "", NaN, null and undefined. Any of them can be a perfectly valid value in some problem, and a truthiness test quietly treats them all as "missing".

Sample tests

Sample 1

Input

4 0 9 2

Expected output

0

The smallest reading is the 0 in second place. The broken program walks straight past it and reports 2 instead.

Sample 2

Input

7 3 11

Expected output

3

No reading is 0 here, so the broken program happens to get this one right — which is exactly why the bug survived.

Your solution

Run tries the first sample. Submit grades against every sample and the hidden tests. Your code is saved in this browser as you go. This problem accepts more than one language: pick yours above the editor, and each keeps its own work while this page is open.

Solve inYour work in each language is kept while this page is open.
Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

More problems

All practice problems →