programming

Modulo of Negative Numbers

How modulo and remainder differ for negative numbers, why languages disagree and how to avoid subtle wraparound bugs.

June 2025

The modulo (often just called “mod”) gives the remainder of a division. In 1801 Gauss published a book covering modular arithmetics. Later a widely accepted mathematical definition was given by Donald Knuth:

mod(a, n) = a - n * floor(a / n)

An integer division followed by multiplication finds the largest multiple of n that fits into a. Subtracting that from a yields the remainder - the modulo.

That sounds straightforward enough. But there’s a subtlety hiding in that floor that trips up programmers across languages.

Remainder vs modulo

Most programming languages use the % operator and call it “modulo”, but what they actually implement is the remainder of a truncated division. Truncated division rounds toward zero, while the mathematical modulo uses floored division (rounding toward negative infinity). For positive numbers the results are identical. For negative numbers, they diverge.

Consider -13 mod 3. The floored division gives floor(-13/3) = -5, so the modulo is -13 - 3 * (-5) = 2. A positive result. The truncated division gives trunc(-13/3) = -4, so the remainder is -13 - 3 * (-4) = -1. A negative result.

This is the root of a whole class of bugs.

Restricting bounds

In programming, the modulo operator is commonly used to wrap an index around the bounds of an array or ring buffer.

values = [ 3, 4, 5 ]
index = 5
value_at_index = values[ index % values.length ]

For the above example 5 mod 3 = 2 following the definition is 5 - floor(5/3)*3 = 2. No matter the value of index, the array bounds are met.

But is that really the case?

What happens if the dividend is negative? Turns out the result of the modulo operation on negative numbers depends on the language you are using.

While the code looks pretty much the same across languages, the results fall into mostly two camps.

Language 13 mod 3 -13 mod 3 13 mod -3 -13 mod -3
C 1 -1 1 -1
C# 1 -1 1 -1
C++ 1 -1 1 -1
Elixir 1 -1 1 -1
Erlang 1 -1 1 -1
Go 1 -1 1 -1
Java 1 -1 1 -1
Javascript 1 -1 1 -1
Kotlin 1 -1 1 -1
Nim 1 -1 1 -1
OCaml 1 -1 1 -1
PHP 1 -1 1 -1
Rust 1 -1 1 -1
Scala 1 -1 1 -1
Swift 1 -1 1 -1
V 1 -1 1 -1
Crystal 1 2 -2 -1
Haskell 1 2 -2 -1
Lua 1 2 -2 -1
Python 1 2 -2 -1
Ruby 1 2 -2 -1
Dart 1 2 1 2

The first group (C, Java, JavaScript, etc.) implements truncated division and the remainder takes the sign of the dividend. The second group (Python, Ruby, etc.) implements floored division and the result takes the sign of the divisor, matching the more mathematical definition.

Dart is a bit of an outlier. Its % operator always returns a non-negative result, regardless of the sign of either operand.

Zig’s principled approach

Zig deserves a special mention for being the most explicit about the distinction. Instead of picking one behavior and hoping developers remember which one it is, Zig provides two separate builtins: @rem for the truncated remainder and @mod for the floored modulo. If you pass a negative divisor, both operations produce a compile-time error. No ambiguity, no surprises.

Zig 13 mod 3 -13 mod 3 13 mod -3 -13 mod -3
@rem 1 -1 error error
@mod 1 2 error error

This is arguably the most clear design there is.

Language-level fixes

Some languages provide built-in alternatives to the default % behavior. Java added Math.floorMod() in Java 8, which gives the mathematically correct floored modulo. So if you’re a Java developer bitten by this before - there’s a one-liner fix now.

Math.floorMod(-13, 3) // returns 2, not -1

Python and Ruby don’t need this since their % already does floored division by default.

For languages without a built-in, a simple and efficient workaround is to check the sign.

int mod(a, b) {
  c = a % b
  return (c < 0) ? c + b : c
}

Alternatively, you can apply the modulo twice.

int mod(a, b) {
  return ((a % b) + b) % b
}

The even/odd trap

Another related pitfall is testing whether a number is odd using the modulo operator. Given that -13 % 2 returns -1 in many languages, you should always compare against 0 rather than 1.

bool is_odd(int n) {
    return n % 2 != 0; // correct: works for both 1 and -1
}

If performance matters and you’re dealing with powers of two, the modulo can be replaced with a bitwise operation since x % 2^n == x & (2^n - 1) for positive divisors. So a faster is_odd becomes:

bool is_odd(int n) {
    return (n & 1) != 0; // note the parentheses to ensure precedence
}

In summary

The modulo operator is one of those things that seems simple until it isn’t. The majority of languages implement truncated remainder rather than the mathematical modulo. The difference only shows up with negative numbers, exactly the path that is often not tested for.

Know which camp your language falls into, use built-in alternatives like Math.floorMod() where available, and when in doubt - write a small wrapper. For a deeper dive, see the Wikipedia article on the modulo operation.

selected photo