Why -7 % 3 gives different answers in different languages

-7 % 3 is 2 in Python but -1 in JavaScript, Java, C and Go. Truncated, floored and Euclidean division explained, and how to get a non-negative remainder.

DevelopmentNumbers

Walk backwards around an array with (i - 1) % n, and when i is 0, Python gives n - 1 while JavaScript gives -1 and reads undefined. Once a negative number is involved, languages define % differently.

Which way the quotient is rounded

Divide an integer a by a non-zero integer b, and the integer quotient q and remainder r must satisfy a = b × q + r. Adding |r| < |b| still does not pin down one answer. For -7 ÷ 3, both (q = -2, r = -1) and (q = -3, r = 2) fit. What decides the remainder is how the real quotient, -2.33…, is turned into an integer.

Method Quotient q Sign of r -7 ÷ 3 7 ÷ -3
Truncated rounded toward zero follows the dividend, on the left q -2, r -1 q -2, r 1
Floored rounded toward −∞ follows the divisor, on the right q -3, r 2 q -3, r -2
Euclidean chosen so 0 ≤ r < |b| never negative q -3, r 2 q -2, r 1

All three satisfy a = b × q + r, but only Euclidean division always gives a non-negative remainder. With two positive operands, they all agree.

What each language picked

Language -7 % 3 Method
Python 2 floored, paired with //
JavaScript, Java, C, C++, Go -1 truncated
JavaScript BigInt -1n (-7n % 3n) truncated

If a language has an operator that returns the integer quotient, such as Python’s //, integer / in Java, C, C++ and Go, or BigInt /, that quotient and % satisfy the identity above. In C and C++, this is conditional on the quotient being representable.

Plain JavaScript numbers are different. -7 / 3 is not an integer quotient but the floating-point value -2.33…, so (a / b) * b + a % b is not this integer identity. The % operation truncates the exact mathematical quotient independently. How floats are stored is covered in our floating-point post.

Where it bites

An odd-number check written as n % 2 == 1 fails in truncating languages because -3 leaves -1. n % 2 != 0 works in all of them.

When you need a value from 0 to n − 1, as with a circular index, add n only when the remainder is negative.

// For circular indexes. n is a positive integer.
function wrapIndex(i, n) {
  const r = i % n;
  return r < 0 ? r + n : r + 0; // + 0 turns -0 into 0
}

wrapIndex(-1, 5); // 4

When a negative number divides exactly, as in -5 % 5, JavaScript returns -0. That still works as an index, but Object.is(-0, 0) is false, so the helper adds 0 to remove the sign.

Standard-library functions are also available. Math.floorMod(-7, 3) and Rust’s (-7i32).rem_euclid(3) both return 2. They part ways when the divisor is negative. floorMod uses floored division, so Math.floorMod(4, -3) is -2. rem_euclid is Euclidean, so 4i32.rem_euclid(-3) is 1.

Specifications and documentation

Back to the blog