Remainder operator vs. modulo operator (with JavaScript code)

[2019-08-06] dev, javascript
(Ad, please don’t block)

You may have read that JavaScript’s % operator is a remainder operator, not a modulo operator. This blog post explains what that means.

Overview: two operators  

Let’s assume there are two operators that are very similar:

  • The remainder operator rem
  • The modulo operator mod

If both operands have the same signs, then the operators produce the same results:

> 5 rem 3
2
> 5 mod 3
2

> -5 rem -3
-2
> -5 mod -3
-2

If, however, they have different signs, then the result of rem has the same sign as the first operand, while the result of mod has the same sign as the second operand:

> -5 rem 3
-2
> -5 mod 3
1

> 5 rem -3
2
> 5 mod -3
-1

Why is that? Read on.

The remainder operator rem  

We’ll first take a closer look at the rem operator:

dividend rem divisor

In order to compute the remainder, we use the following two equations:

dividend = divisor * quotient + remainder
|remainder| < |divisor|

dividend, divisor, quotient, and remainder are all integers (for the sake of this blog post).

In order to compute the remainder we must find the quotient:

remainder = dividend - divisor * quotient

And we do so by dividing the dividend by the divisor. Math.trunc() ensures that the resulting quotient is an integer.

Example 1: 5 rem 3 === 2

const dividend = 5;
const divisor = 3;
const quotient = Math.trunc(dividend / divisor);
assert.equal(quotient, 1);

Example 2: -5 rem 3 === -2

const dividend = -5;
const divisor = 3;
const quotient = Math.trunc(dividend / divisor);
assert.equal(quotient, -1);

The modulo operator mod  

The modulo operator is based on the same equations, but it uses Math.floor() to compute quotients:

  • If both dividend and divisor are positive, the modulo operator produces the same results as the remainder operator (example 3).
  • If, however, dividend and divisor have different signs, then the results are different (example 4).

The reason for that is that Math.trunc() and Math.floor() produce the same results for positive numbers, but different results for negative numbers.

Example 3: 5 mod 3 === 2 (dividend is 5, divisor is 3)

const dividend = 5;
const divisor = 3;
const quotient = Math.floor(dividend / divisor);
assert.equal(quotient, 1);

Example 4: -5 mod 3 === 1 (dividend is −5, divisor is 3)

const dividend = -5;
const divisor = 3;
const quotient = Math.floor(dividend / divisor);
assert.equal(quotient, -2);

An intuitive explanation of modulo  

Modulo can also be viewed as an operation that maps an arbitrary number into a given range – for example:

x mod 3

maps x into the range

[0,3) = {0,1,2}

That is, zero is included, 3 is excluded.

If x is already inside the range, performing the mapping is simple:

> 0 mod 3
0
> 2 mod 3
2

If x is greater than or equal to the upper boundary of the range, then the upper boundary is subtracted from x until it fits into the range:

> 4 mod 3
1
> 7 mod 3
1

That means we are getting the following mapping for non-negative integers:

0 1 2 3 4 5 6 7
0 1 2 0 1 2 0 1

This is how the mapping is extended so that it also covers negative integers:

-7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7
 2  0  1  2  0  1  2  0  1  2  0  1  2  0  1
> -1 mod 3
2
> -3 mod 3
0
> -4 mod 3
2

x rem 3 maps x as follows:

-7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7
-1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1

Negative right-hand side  

x mod -3 maps x to the range (-3, 0]

-7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7
-1  0 -2 -1  0 -2 -1  0 -2 -1  0 -2 -1  0 -2

x rem -3 has the following mapping (the same as x rem 3):

-7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7
-1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1

Uses of the modulo operation in JavaScript  

The ECMAScript specification uses modulo several times – for example:

  • To convert the operands of the >>> operator to unsigned 32-bit integers (via x mod 2**32):

    > 2**32 >>> 0
    0
    > (2**32)+1 >>> 0
    1
    > (-1 >>> 0) === (2**32)-1
    true
    
  • To convert arbitrary numbers so that they fit into Typed Arrays. For example, x mod 2**8 is used to convert numbers to unsigned 8-bit integers (after first converting them to integers):

    const tarr = new Uint8Array(1);
    
    tarr[0] = 256;
    assert.equal(tarr[0], 0);
    
    tarr[0] = 257;
    assert.equal(tarr[0], 1);
    

Conclusions and further reading  

Which of rem and mod is supported and how depends on the programming language:

  • JavaScript‘s % operator is a remainder operator.
  • Python’s % operator is a modulo operator.

If you want to read more about remainder and modulo: