Skip to content

03 Beginner The Hundred

The Remainder That Went Negative

the wrap-around that forgot to wrap

#include <iostream>

int main() {
    int sample[3] = {70, 80, 90};   // ring buffer holding the last three readings

    int step = -7;         // seven steps back around the ring
    int slot = step % 3;   // wrap onto 0, 1 or 2

    std::cout << "laps: " << step / 3 << '\n';
    std::cout << "slot: " << slot << '\n';
    std::cout << "read: " << sample[slot] << '\n';
}

Run it. Which slot does the ring land on?

Answer

laps: -2, slot: -1, and typically read: 0 (GCC 11.5 on x86-64, -O0). The wrap landed one element before the array — and nothing complained.

Why

C++ integer division truncates toward zero, not downward (see entry 01), so -7 / 3 is -2 where a floor would give -3. The remainder then has to satisfy (a / b) * b + a % b == a, which forces % to carry the sign of the dividend: -7 % 3 is -1, not the 2 Python would hand you. So sample[slot] reads one int before the array — undefined behavior, and here a quiet 0 with no crash and nothing in a log to raise an eyebrow, which is exactly how this survives review. Change compiler or optimization level and the number changes with it: 167772160 at GCC -O1, -7 under Clang 18 at -O0, 540697697 under Clang at -O2. GCC's -Wall says nothing at -O0; at -O2 the index folds to a constant and it finally speaks up with warning: array subscript -1 is below array bounds of 'int [3]' [-Warray-bounds] — a luxury you lose the moment step arrives at runtime.

Before C++11 the rounding direction for negative operands was implementation-defined; C++11 pinned it to truncation.

The fix

Push the remainder back into range — the + 3 only matters when the first % went negative, and the second % cancels it again when it didn't:

int slot = ((step % 3) + 3) % 3;   // 0, 1 or 2 for every step, forward or back

if (slot < 0) slot += 3; does the same job with a branch. To find the ones you missed, let the sanitizer read your subscripts:

$ g++ -std=c++17 -fsanitize=undefined main.cpp -o demo && ./demo
main.cpp:11:41: runtime error: index -1 out of bounds for type 'int [3]'

Takeaway: % follows the sign of the dividend, not the divisor — wrap an index with ((i % n) + n) % n.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry