Clean, efficient algorithm for wrapping integers in C
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Integer wrapping usually means taking a value that may move outside a range and folding it back into that range. A common example is turning an index like -1 into the last slot of a circular buffer, or turning n into 0 when valid indexes are 0 through n - 1.
The clean solution depends on the range. For arbitrary modulus m, the standard formula for wrapping into [0, m) is based on remainder arithmetic. In C and C++, the important detail is that negative values need special handling because % alone does not produce a mathematical modulo in the way many programmers first expect.
Wrap Into [0, m) Safely
For positive m, the standard wrap formula is:
Why the double %? Because x % m can be negative when x is negative. Adding m moves the result back into a nonnegative range, and the final % m handles the case where the first remainder was already nonnegative.
Examples for m = 5:
- '
wrap(0, 5)gives0' - '
wrap(6, 5)gives1' - '
wrap(-1, 5)gives4' - '
wrap(-6, 5)gives4'
That is the general-purpose answer for circular indexing.
Wrap Into An Arbitrary Inclusive Range
If the desired range is [min, max], first shift to zero, wrap there, then shift back:
This is useful for values such as day-of-week numbers, menu positions, or game board coordinates where the logical range does not start at zero.
Power-Of-Two Shortcut
If the modulus is a power of two and the values are nonnegative or you are working with unsigned arithmetic, a bit mask can be faster and simpler:
This only works when size is a power of two, such as 8, 16, or 32. It is a great fit for ring buffers and low-level performance-sensitive code, but it is not a general replacement for modulo arithmetic.
Prefer Clarity Unless Profiling Says Otherwise
The modulo-based solution is already constant time and usually fast enough. In most application code, the cleanest formula is the right one. Reach for bit tricks only when the range properties make them valid and you actually care about the difference.
The more important optimization is often avoiding bugs around negative values, not shaving a tiny amount of CPU time.
Unsigned And Signed Behavior
Unsigned integer types already have defined wraparound semantics at the hardware level, but that is not the same as wrapping into an arbitrary application range. Range wrapping should still be expressed intentionally so the code says what range you actually mean.
Common Pitfalls
- Using
x % mdirectly and forgetting it can be negative. - Forgetting to validate that
mor the range width is positive. - Applying the bit-mask shortcut when the modulus is not a power of two.
- Using signed overflow as if it were a wrapping guarantee.
- Writing clever wrap code that is hard to read and easy to misuse.
Summary
- The standard wrap formula for
[0, m)is((x % m) + m) % m. - For
[min, max], shift into zero-based space, wrap, then shift back. - Bit masking is a valid shortcut only for power-of-two ranges.
- Negative values are the main reason naive
%code fails. - Prefer clear modulo-based code unless profiling proves you need something lower-level.

