Why can a digit-stripping recursion with an n == 0 base case never terminate on negative input?
answer
- name the measure before checking the code
- how does dividing a negative round
- one value maps to itself
- the range is not symmetric
- negating the smallest value
basics
~20 sBecause the termination argument silently assumes integer division rounds toward zero. Under rounding toward negative infinity the value sticks at -1 and never equals 0. Negating the input first is not a safe fix: the most-negative fixed-width value has no positive counterpart.
solid answer
~50 sThe termination argument is "the magnitude strictly decreases and lands on zero", and that argument depends on an arithmetic property the code never states. If integer division truncates toward zero, a negative account number descends -2517, -251, -25, -2, 0 and terminates. If division rounds toward negative infinity, it goes -2517, -252, -26, -3, -1, -1, -1 — the value -1 is a fixed point, the magnitude stops decreasing, and the `n == 0` test is never satisfied. Under that rule the extracted digits are wrong too, so this is not only a termination bug. Negating the input on entry is an unsafe fix: fixed-width two's-complement ranges are asymmetric, so the most-negative value has no positive counterpart and negating it overflows. I would base on a region rather than a point — stop once the magnitude is below ten — and test zero and both extremes.
go deeper
Know that a base case testing equality against a single value can be missed entirely, and that negative inputs are a distinct case to think about rather than a variation of positive ones.
Explain the measure and where it fails: the magnitude only decreases under one of two legitimate rounding rules, and under the other, -1 maps to itself and the descent stalls there forever.
Demonstrate the full argument: name the measure, surface the arithmetic assumption, identify the fixed point, reject the negation fix on range asymmetry, and specify the extreme-value tests you would require before approving.
Own the policy angle. Where numeric recursions run over externally supplied values, decide whether the team pins arithmetic assumptions in code, standardises on region-shaped base conditions, and mandates an extreme-value test row — the cheap convention that retires the whole defect class.
## The claim being made, spelled out A digit-by-digit reduction — peeling one decimal digit per call off a signed account number to accumulate a checksum, say — carries an implicit termination argument: *the magnitude of `n` strictly decreases on every call and eventually equals zero, where the base case fires*. That argument has three parts, and the negative case attacks the first two. ## Rounding decides whether the measure decreases Integer division of a negative operand is defined two different ways, and both are in wide production use. - **Truncation toward zero**: -2517 becomes -251, then -25, then -2, then 0. The magnitude strictly decreases and hits the base. The recursion terminates. - **Rounding toward negative infinity (floor)**: -2517 becomes -252, then -26, then -3, then **-1**, and -1 divided by ten floors to -1 again. The value is a fixed point. The magnitude has stopped decreasing, so there is no longer a decreasing measure at all, and the `n == 0` equality is never satisfied. The lesson generalises past this one bug: *a termination argument is only as strong as the arithmetic it assumes*. The code says `n / 10` and the reviewer reads "gets smaller", but "gets smaller" is a property of the operation's rounding rule, not of the syntax. This is one of the few places where two mainstream language families genuinely disagree — Python floors, while C, Java and Go truncate toward zero — so the same recursion is correct in one and a hang in the other. The same rounding rule also corrupts the digits, which is worth noticing because it means the bug is not confined to termination. Under floor semantics the remainder is non-negative: -25 decomposes as 10 × (-3) + 5, so the digit extracted is 5 where the intended digit was 2. Termination is the loud symptom; the wrong checksum would have been the quiet one. ## Why negating on entry is a trap The reflex fix is to normalise the sign — take the magnitude once at the entry point, then recurse over a non-negative value. On fixed-width two's-complement integers this is unsafe, because the representable range is asymmetric: there is exactly one more negative value than positive, so the most-negative value has no positive counterpart. Negating it overflows — it either wraps back to itself, silently reproducing the original problem, or is outright undefined depending on the environment. A normalisation step that fails on precisely the extreme input you were trying to protect is worse than no normalisation, because it looks like due diligence. Safe alternatives: widen to a larger type before negating; or do not negate at all — recurse on the negative side, extracting digits by magnitude, and apply the sign once to the assembled result. ## Base on a region, not a point All of this argues for the same structural fix that fixes stride bugs: make the base case a **region** the step cannot jump over or stall inside. Stopping when the magnitude is below ten terminates from either sign under either rounding rule, because that condition is true of a whole neighbourhood rather than a single point. Equality bases are fragile precisely when the step's behaviour near the boundary is not fully pinned down — a stride bigger than one, a rounding rule you did not specify, a floating quantity that never lands exactly. ## What a senior answer adds The reason this question sorts candidates is that the mechanical answer ("negatives don't reach zero") is only the surface. What an interviewer is listening for: 1. **The measure is named** — magnitude toward zero — rather than implied. 2. **The assumption is surfaced** — the measure decreases only under one of two legitimate rounding rules, which the code does not document. 3. **The fixed point is identified** — -1 maps to itself, which is a stronger statement than "it goes negative". 4. **The obvious fix is examined and rejected** — asymmetric range, negation overflow at the extreme. 5. **The test set follows** — zero, single digits of each sign, and both representable extremes, because this whole family of defect lives at values that random and mid-range testing never generate. That last point is the practical payoff. Extremes and degenerate values are a small, finite, cheap set to enumerate, and they catch base-case coverage bugs, sign bugs and overflow bugs in the same pass.
- Why is negating the input a fragile way to normalise the sign?Fixed-width two's-complement holds one more negative value than positive, so the most-negative value has no positive counterpart and negating it overflows — wrapping back to itself in some environments and undefined in others. Either widen the type before negating, or avoid negation entirely by extracting digits on the negative side and applying the sign once to the final result.
- What base condition would you write instead of a bare n == 0?A region rather than a point: stop once the magnitude is below ten and handle that final digit directly. That condition is true of a whole neighbourhood, so it terminates from either sign and under either rounding rule, instead of depending on the step landing exactly on one value.
- What test inputs would you insist on for a recursion over signed integers?Zero, a single digit of each sign, a multi-digit value of each sign, and both representable extremes. This family of defect — base-case coverage, sign handling, negation overflow — lives entirely at the boundaries of the domain, and mid-range or randomly generated inputs essentially never produce them.
saying these in an interview costs you the question
- Assumes integer division always truncates toward zero
- Says negating the input always normalises the sign safely
- Claims the magnitude decreases without checking the rounding rule
- Treats zero and the extreme values as ordinary inputs
- Believes an equality base condition catches everything below it