Modulo facts for kids
In computing, the modulo operation helps us find the remainder when one number is divided by another. Think of it like this: if you have 5 cookies and you divide them among 2 friends, each friend gets 2 cookies, and you have 1 cookie left over. That "1" is the remainder, and that's what the modulo operation gives you! The number you divide by is called the modulus.
When we have two positive numbers, let's say a and n, a modulo n (often written as a mod n) is the leftover part after you divide a by n. Here, a is the number being divided (the dividend), and n is the number you're dividing by (the divisor).
For example, "5 mod 2" equals 1. Why? Because 5 divided by 2 is 2 with a remainder of 1. If you see "9 mod 3", the answer is 0. This is because 9 divided by 3 is exactly 3, with no remainder left.
Usually, we use whole numbers for modulo operations. However, many computer systems can now use other types of numbers too. When you do a modulo operation with a number n, the result will always be a whole number between 0 and n − 1. For instance, a mod 1 is always 0. But be careful: a mod 0 is usually not allowed and can cause an error in computer programs!
Things get a bit tricky when one of the numbers (a or n) is negative. Different programming languages handle these situations in different ways.
Contents
How the Modulo Operation Works Differently
In mathematics, the result of a modulo operation is part of a group of numbers that are all "the same" in a special way. We usually pick the smallest non-negative number from this group as the answer. But computers and calculators can define the modulo operation in various ways, depending on the programming language or the computer's parts.
Almost all computer systems follow these rules for division:
- Both the quotient (the result of the division) and the remainder must be whole numbers.
- The original number a must equal the divisor n multiplied by the quotient q, plus the remainder r. So, a = n q + r.
- The absolute value (size) of the remainder must be smaller than the absolute value of the divisor.
However, if the remainder isn't zero, there's still a choice to make: should the remainder be positive or negative? In math, we always choose a positive remainder. But in computing, programming languages decide based on the signs of a or n. For example, some languages like Pascal always give a positive remainder, even if you divide by a negative number. Other languages, like C90, let the computer decide what happens when n or a is negative. Dividing by 0 is usually not allowed in most systems.
Here are some common ways computers define how to find the quotient and remainder:
- Truncated Division:
This method rounds the quotient (the result of the division) towards zero.
With this method, the remainder will always have the same sign as the number being divided (the dividend).
- Floored Division:
Donald Knuth, a famous computer scientist, prefers this method. Here, the quotient is always rounded down to the nearest whole number.
With this method, the remainder will always have the same sign as the number you're dividing by (the divisor).
- Euclidean Division:
This method is promoted by Raymond T. Boute. It's designed so that the remainder is always non-negative (0 or positive).
- Rounded Division:
Some languages like Common Lisp and IEEE 754 use this. The quotient is rounded to the nearest whole number.
With this method, the remainder will be between negative half of n and positive half of n. Its sign depends on which side of zero it falls.
- Ceiling Division:
Common Lisp also uses this. The quotient is always rounded up to the nearest whole number.
With this method, the remainder will have the opposite sign of the divisor.
Experts like Daan Leijen say that Euclidean division is often the best because it's very consistent and has useful math properties. Floored division is also considered good. Even though truncated division is used a lot, it's often seen as less ideal than the others.
How We Write Modulo Operations
Many calculators have a special button or function called `mod()` or `MOD()`. In programming languages, you might see it written as `mod(a, n)`. Some languages also use symbols like "%", "mod", or "Mod" as an operator, for example, `a % n` or `a mod n`.
If a programming environment doesn't have a built-in modulo function, programmers can create one using the division methods we talked about earlier.
Common Mistakes with Modulo
When the result of a modulo operation has the same sign as the number being divided (like in truncated division), it can sometimes lead to unexpected errors.
For example, imagine you want to check if a number is odd. You might think you can just check if the remainder when divided by 2 is 1:
bool is_odd(int n) {
return n % 2 == 1;
}
But this can be wrong! If n is a negative odd number, like -5, and the modulo operation gives the same sign as the dividend (truncated definition), then -5 mod 2 would be -1, not 1. In this case, the function would incorrectly say that -5 is not odd.
A better way to check if a number is odd is to see if the remainder is not 0. This works because a remainder of 0 is always 0, no matter the signs:
bool is_odd(int n) {
return n % 2 != 0;
}
Another way is to check if the remainder is either 1 or -1 (since odd numbers will always have one of these remainders when divided by 2):
bool is_odd(int n) {
return n % 2 == 1 || n % 2 == -1;
}
Or, even simpler, you can often just use the result of `n % 2` as a true/false value, where any non-zero value means "true":
bool is_odd(int n) {
return n % 2;
}
Making Modulo Operations Faster
Sometimes, computers calculate modulo by doing a full division first. But for special cases, there are faster ways! For example, if you need to find the modulo of a number by a powers of 2 (like 2, 4, 8, 16, etc.), you can use a bitwise AND operation. This is much quicker on some computer hardware.
For a positive whole number x, and a power of 2 (like 2n), this works: `x % 2n == x & (2n - 1)`
Here are some examples:
- `x % 2 == x & 1`
- `x % 4 == x & 3`
- `x % 8 == x & 7`
If a computer or software can do bitwise operations faster than modulo, these alternative forms will make calculations quicker.
Special programs called compilers can sometimes automatically change your code to use these faster bitwise operations if they see you're doing a modulo by a power of two. This means you can write clear code, and the computer will still make it run fast! However, this trick doesn't always work if the number you're dividing (the dividend) can be negative, unless it's an unsigned integer (a number that can only be positive).
Properties of Modulo Operations
Just like other math operations, modulo operations have special rules and properties. These can be very useful in cryptography (like for secure communication). These rules usually apply when a and n are whole numbers.
- Identity:
- (a mod n) mod n = a mod n (Doing modulo twice by the same number doesn't change the result).
- nx mod n = 0 (If you raise n to any positive whole number power and then modulo by n, the remainder is 0).
- Inverse:
- [(-a mod n) + (a mod n)] mod n = 0 (Adding a number's negative modulo to its positive modulo gives 0).
- Distributive:
- (a + b) mod n = [(a mod n) + (b mod n)] mod n (You can add first, then modulo, or modulo each number then add, then modulo again).
- ab mod n = [(a mod n)(b mod n)] mod n (You can multiply first, then modulo, or modulo each number then multiply, then modulo again).
Modulo in Programming Languages
Different programming languages handle the modulo operation in various ways, especially when dealing with negative numbers or decimals. The table below shows how some popular languages define their modulo or remainder operators.
Language | Operator | Whole Numbers | Decimal Numbers | Definition |
---|---|---|---|---|
ABAP |
|
Yes | Yes | Euclidean |
ActionScript |
|
Yes | No | Truncated |
Ada |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
ALGOL 68 | ,
|
Yes | No | Euclidean |
AMPL |
|
Yes | No | Truncated |
APL | | |
Yes | No | Floored |
AppleScript |
|
Yes | No | Truncated |
AutoLISP |
|
Yes | No | Truncated |
AWK |
|
Yes | No | Truncated |
bash |
|
Yes | No | Truncated |
BASIC |
|
Yes | No | Undefined |
bc |
|
Yes | No | Truncated |
C C++ |
,
|
Yes | No | Truncated |
(C) (C++) |
No | Yes | Truncated | |
(C) (C++) |
No | Yes | Rounded | |
C# |
|
Yes | Yes | Truncated |
|
No | Yes | Rounded | |
Clarion |
|
Yes | No | Truncated |
Clean |
|
Yes | No | Truncated |
Clojure |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
COBOL |
|
Yes | No | Floored |
CoffeeScript |
|
Yes | No | Truncated |
|
Yes | No | Floored | |
ColdFusion | ,
|
Yes | No | Truncated |
Common Lisp |
|
Yes | Yes | Floored |
|
Yes | Yes | Truncated | |
Crystal | ,
|
Yes | Yes | Floored |
|
Yes | Yes | Truncated | |
D |
|
Yes | Yes | Truncated |
Dart |
|
Yes | Yes | Euclidean |
|
Yes | Yes | Truncated | |
Eiffel |
|
Yes | No | Truncated |
Elixir |
|
Yes | No | Truncated |
|
Yes | No | Floored | |
Elm |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Erlang |
|
Yes | No | Truncated |
|
No | Yes | Truncated (same as C) | |
Euphoria |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
F# |
|
Yes | Yes | Truncated |
|
No | Yes | Rounded | |
Factor |
|
Yes | No | Truncated |
FileMaker |
|
Yes | No | Floored |
Forth |
|
Yes | No | Implementation defined |
|
Yes | No | Floored | |
|
Yes | No | Truncated | |
Fortran |
|
Yes | Yes | Truncated |
|
Yes | Yes | Floored | |
Frink |
|
Yes | No | Floored |
GLSL |
|
Yes | No | Undefined |
|
No | Yes | Floored | |
GameMaker Studio (GML) | ,
|
Yes | No | Truncated |
GDScript (Godot) |
|
Yes | No | Truncated |
|
No | Yes | Truncated | |
|
Yes | No | Floored | |
|
No | Yes | Floored | |
Go |
|
Yes | No | Truncated |
|
No | Yes | Truncated | |
|
Yes | No | Euclidean | |
Groovy |
|
Yes | No | Truncated |
Haskell |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
(GHC) |
No | Yes | Floored | |
Haxe |
|
Yes | No | Truncated |
HLSL |
|
Yes | Yes | Undefined |
J | | |
Yes | No | Floored |
Java |
|
Yes | Yes | Truncated |
|
Yes | No | Floored | |
JavaScript TypeScript |
|
Yes | Yes | Truncated |
Julia |
|
Yes | Yes | Floored |
,
|
Yes | Yes | Truncated | |
Kotlin | ,
|
Yes | Yes | Truncated |
|
Yes | Yes | Floored | |
ksh |
|
Yes | No | Truncated (same as POSIX sh) |
|
No | Yes | Truncated | |
LabVIEW |
|
Yes | Yes | Truncated |
LibreOffice |
|
Yes | No | Floored |
Logo |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Lua 5 |
|
Yes | Yes | Floored |
Lua 4 |
|
Yes | Yes | Truncated |
Liberty BASIC |
|
Yes | No | Truncated |
Mathcad |
|
Yes | No | Floored |
Maple | (by default),
|
Yes | No | Euclidean |
|
Yes | No | Rounded | |
|
Yes | Yes | Rounded | |
Mathematica |
|
Yes | No | Floored |
MATLAB |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Maxima |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Maya Embedded Language |
|
Yes | No | Truncated |
Microsoft Excel |
|
Yes | Yes | Floored |
Minitab |
|
Yes | No | Floored |
Modula-2 |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
MUMPS |
|
Yes | No | Floored |
Netwide Assembler (NASM, NASMX) | , (unsigned) |
Yes | No | N/A |
(signed) |
Yes | No | Implementation-defined | |
Nim |
|
Yes | No | Truncated |
Oberon |
|
Yes | No | Floored-like |
Objective-C |
|
Yes | No | Truncated (same as C99) |
Object Pascal, Delphi |
|
Yes | No | Truncated |
OCaml |
|
Yes | No | Truncated |
|
No | Yes | Truncated | |
Occam |
|
Yes | No | Truncated |
Pascal (ISO-7185 and -10206) |
|
Yes | No | Euclidean-like |
Programming Code Advanced (PCA) |
|
Yes | No | Undefined |
Perl |
|
Yes | No | Floored |
|
No | Yes | Truncated | |
Phix |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
PHP |
|
Yes | No | Truncated |
|
No | Yes | Truncated | |
PIC BASIC Pro |
|
Yes | No | Truncated |
PL/I |
|
Yes | No | Floored (ANSI PL/I) |
PowerShell |
|
Yes | No | Truncated |
Programming Code (PRC) |
|
Yes | No | Undefined |
Progress |
|
Yes | No | Truncated |
Prolog (ISO 1995) |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
PureBasic | ,
|
Yes | No | Truncated |
PureScript |
|
Yes | No | Euclidean |
Pure Data |
|
Yes | No | Truncated (same as C) |
|
Yes | No | Floored | |
Python |
|
Yes | Yes | Floored |
|
No | Yes | Truncated | |
Q# |
|
Yes | No | Truncated |
R |
|
Yes | Yes | Floored |
Racket |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Raku |
|
No | Yes | Floored |
RealBasic |
|
Yes | No | Truncated |
Reason |
|
Yes | No | Truncated |
Rexx |
|
Yes | Yes | Truncated |
RPG |
|
Yes | No | Truncated |
Ruby | ,
|
Yes | Yes | Floored |
|
Yes | Yes | Truncated | |
Rust |
|
Yes | Yes | Truncated |
|
Yes | Yes | Euclidean | |
SAS |
|
Yes | No | Truncated |
Scala |
|
Yes | No | Truncated |
Scheme |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Scheme R6RS |
|
Yes | No | Euclidean |
|
Yes | No | Rounded | |
|
No | Yes | Euclidean | |
|
No | Yes | Rounded | |
Scratch |
|
Yes | Yes | Floored |
Seed7 |
|
Yes | Yes | Floored |
|
Yes | Yes | Truncated | |
SenseTalk |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
(POSIX) (includes bash, mksh, &c.) |
|
Yes | No | Truncated (same as C) |
Smalltalk |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
Snap! |
|
Yes | No | Floored |
Spin |
|
Yes | No | Floored |
Solidity |
|
Yes | No | Floored |
SQL (SQL:1999) |
|
Yes | No | Truncated |
SQL (SQL:2011) |
|
Yes | No | Truncated |
Standard ML |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
|
No | Yes | Truncated | |
Stata |
|
Yes | No | Euclidean |
Swift |
|
Yes | No | Truncated |
|
No | Yes | Rounded | |
|
No | Yes | Truncated | |
Tcl |
|
Yes | No | Floored |
tcsh |
|
No | No | Truncated |
Torque |
|
Yes | No | Truncated |
Turing |
|
Yes | No | Floored |
Verilog (2001) |
|
Yes | No | Truncated |
VHDL |
|
Yes | No | Floored |
|
Yes | No | Truncated | |
VimL |
|
Yes | No | Truncated |
Visual Basic |
|
Yes | No | Truncated |
WebAssembly | , (unsigned) |
Yes | No | N/A |
, (signed) |
Yes | No | Truncated | |
x86 assembly |
|
Yes | No | Truncated |
XBase++ |
|
Yes | Yes | Truncated |
|
Yes | Yes | Floored | |
Zig | ,
|
Yes | Yes | Truncated |
Z3 theorem prover | ,
|
Yes | No | Euclidean |
Many computer systems also offer a `divmod` function. This function gives you both the quotient (the result of the division) and the remainder at the same time. Examples include the `IDIV` instruction in x86 architecture and the `divmod()` function in Python.