Understanding Modulo with Negative Numbers
When both operands are positive, all modulo conventions agree. However, when one or both operands are negative, there are two common definitions that produce different results. Understanding this difference is crucial for programmers who work across multiple languages.
Two Definitions of Modulo
Truncated Division (Remainder)
The quotient is truncated toward zero. Used by JavaScript, C, C++, Java, and C#. The result has the same sign as the dividend.
Floored Division (Modulo)
The quotient is floored (rounded toward negative infinity). Used by Python, Ruby, and Haskell's mod. The result has the same sign as the divisor.
When Do They Differ?
The two definitions produce different results only when the dividend and divisor have different signs (one positive and one negative). When both are positive or both are negative, the results are the same.
Specifically, the relationship between the two is:
- If
a % b(truncated) is zero, both definitions give 0. - If
aandbhave the same sign, both definitions give the same result. - If
aandbhave different signs and the truncated remainder is non-zero, then:floored_mod = truncated_rem + b.
Examples with Negative Numbers
-7 mod 3
Truncated: -7 % 3 = -1 (quotient = -2)
Floored: -7 mod 3 = 2 (quotient = -3)
7 mod -3
Truncated: 7 % -3 = 1 (quotient = -2)
Floored: 7 mod -3 = -2 (quotient = -3)
-7 mod -3
Truncated: -7 % -3 = -1 (quotient = 2)
Floored: -7 mod -3 = -1 (quotient = 2)
-10 mod 4
Truncated: -10 % 4 = -2 (quotient = -2)
Floored: -10 mod 4 = 2 (quotient = -3)
Converting Between the Two
If you need the floored modulo in a language that only provides the truncated remainder (like JavaScript), you can use this formula:
floored_mod = ((a % b) + b) % b
This always gives the floored (Python-style) modulo result regardless of the signs of a and b.
Language Reference
- JavaScript:
%gives truncated remainder. Use((a % b) + b) % bfor floored modulo. - Python:
%gives floored modulo. Usemath.fmod(a, b)for truncated remainder. - C/C++:
%gives truncated remainder (since C99/C++11). - Java:
%gives truncated remainder. UseMath.floorMod(a, b)for floored modulo. - Ruby:
%gives floored modulo. Usea.remainder(b)for truncated remainder.
Why Does This Matter?
Understanding the difference is important in many practical scenarios:
- Circular indexing: When wrapping around arrays, floored modulo always gives a non-negative index (when divisor is positive), making it safer for array access.
- Clock arithmetic: Going backwards from 2 o'clock by 5 hours should give 9, not -3. Floored modulo handles this correctly.
- Number theory: Mathematical modular arithmetic typically uses the floored definition where the result is always non-negative.
- Cross-language bugs: Porting code between Python and JavaScript can introduce subtle bugs if this difference is not accounted for.