Number Theory is the Queen of Mathematics.
- Carl Friedrich Gauss
Introduction
Modular Arithmetic was debveloped by Carl Friedrich gauss in 1801. Since then, it has been used extensively to study properties of numbers and classes of numbers
To mention its several applications in Computer Science, Modular Arithmetic allows us to easily create groups, rings and fields which are fundamental building blocks of most modern public-key cryptosystems.
In this and the next few scheduled meets, we are, however, going to talk about applications of number theory and modular arithmetic with respect to competitive programming.
Divisibility
Before directly talking about the topic of Modular Arithmetic let us first revise the concepts on divisibility and the ideas revolving gcd and lcm.
a=bq+r for some (a,b)∃ unique (q,r) where 0<b≤a
Greatest Common Divisor
Problem: Given two numbers a and b find the greatest common divisor of both.
gcd(a,b)=k=1…∞:k∣a∧k∣bmaxk
This brings us to one of the oldest algorithms known to mankind. Euclidean algorithm to find gcd of two numbers.
From our knowledge of divisibility let us formulate the following:
// Make sure that a > b in here.
int gcd(int a, int b)
{
if (b == 0) return a;
return gcd(a, a%b);
}
Extended GCD Algorithm
Given any (a,b) we can always represent the following. To prove this one can use a basic proof by contradiction.
ax+by=gcd(a,b)
Problem: Find these coefficients.
int gcd(int a, int b, int& x, int& y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int x1, y1;
int d = gcd(b, a % b, x1, y1);
x = y1, y = x1 - y1 * (a / b);
return d;
}
Terminology and Notation
nmodmis defined as n−⌊mn⌋∗m, where ⌊x⌋ is the largest integer that doesn't exceed x (This should always produce an integer between 0 and m−1 inclusive).
In mathematical terms, n≡x(modm) if ∃k∈N∪0 such that ∣n−x∣=km.
Also, if we have two expressions f and g then,
f≡g(modm)⟹fmodm=gmodm
In C/C++ % is the modulus operator.
For example 5 % 3 = 2, 10 % 2 = 0, -3 % 2 = -1 and 5 % -3 = 1.
Also, x % 0 is not defined for obvious reasons.
Precedence order:
%/*
+-
Therefore, a + b % m is not equal to (a + b) % m.
Modular Arithmetic
Basic Properties
Let's talk about some basic properties of the modular operation.
a≡a(modm)
a≡b(modm)⟺b≡a(modm)
If a≡b(modm) and b≡c(modm) then a≡c(modm)
1. Addition
((amodm)+(bmodm))modm=(a+b)modm
Proof
Let, a=mq1+r1⟹amodm=r1
and b=mq2+r2⟹bmodm=r2
Thus, LHS=(r1+r2)modm, and on the other hane we have
⁍
2. Subtraction
((amodm)−(bmodm))modm=(a−b)modm
Proof
Let, a=mq1+r1⟹amodm=r1
and b=mq2+r2⟹bmodm=r2
Thus, LHS=(r1−r2)modm, and on the other hane we have
⁍
3. Multiplication
((amodm)×(bmodm))modm=(a×b)modm
Proof
Let, a=mq1+r1⟹amodm=r1
and b=mq2+r2⟹bmodm=r2
Thus, LHS=(r1×r2)modm, and on the other hane we have
This is slightly more complicated, and requires a concept called the "modular multiplicative inverse".
The modular multiplicative inverse of a number a is the number a−1 s.t. a×a−1modm=1. You may notice that this is similar to the concept of a reciprocal, but here we don't want a fraction; we want an integer, specifically an integer between 0 and m−1 inclusive.
We should note that the modular inverse does not always exist. For example, let m=4,a=2. By checking all possible values modulo m is should become clear that we cannot find a−1 satisfying the above equation. It can be proven that the modular inverse exists if and only if aandm are relatively prime, i.e.gcd(a, m) = 1.
But how do you actually find such a number? Bruteforcing all numbers to a prime number close to a billion will usually cause you to exceed the time limit. There are two faster ways to calculate the inverse: the extended GCD algorithm, and Fermat's little theorem.
a−1using Fermat’s Theorem
Fermat's Result : ap−1≡1modp , where p is prime.
ap−1≡1modp
a×ap−2≡1modp
∴We can see that ap−2≡a−1modp
Extended GCD algorithm is explained below.
ax+by=gcd(a,b)=1⟹ax+by≡1(mod b)⟹ax≡1(mod b)
a×a−1≡1(modm)
a×a−1+m×y=1
a×x+b×y=gcd(a,b)
Further Properties
ca≡cb(modn)⟹a≡c(modgcd(c,n)n)
ax≡1(modn) has a unique solution modulo n if and only if gcd(a,n)=1
ax≡b(modn)⟹ax−ny=b and thus will have solutions, if and only if gcd(a,n)=b
ax+by≡r(modn) and cx+dy≡s(modn) has a unique solution modulo x, if and only if gcd(ad−bc,n)=1
Try to prove these on your own!
Theorems and Methods
Chinese Remainder Theorem
x≡a1modn1x≡a2modn2x≡a3modn3....x≡armodnr
Let, N=n1...nr and Ni=niN then, the solution for x mod n1...nr shall be
x=∑aiNixi
where Nixi≡1modni.
Fermat's Theorem
According to fermat's Theorem we have the following which holds true if and only if gcd(a,p)=1.
ap−1≡1modp
Proof Outline
We have a.2a.3a...(p−1)a≡1.2...(p−1)modp.
From the equation above the Fermat's theorem, called formally as Fermat's Little Theorem in contrast with his last theorem, can be easily derived and hence proven.
Backstory: Probably Leibnitz was the first person to find this shit but he never published. I am not quite sure who finally wrote the formal proof of this theorem. Probably, Euler.
More Theorems
If p,q are two primes such that ap≡1(modq) and aq≡1(modp) then,
apq≡1modpq
x2+1≡0 mod p has a solution if and only if p≡1(mod4) and p is an odd prime.
Binary Exponentiation
Binary exponentiation (also known as exponentiation by squaring) is a trick which allows to calculate an using only O(logN) multiplications (instead of O(N) multiplications required by the naive approach).
It also has important applications in many tasks unrelated to arithmetic, since it can be used with any operations that have the property of associativity: X.(Y.Z)=(X.Y).Z
Raising a to the power of n is expressed naively as multiplication by a done n−1 times: an=a×a×a...a. However, this approach is not practical for large a or n.
The idea of binary exponentiation is, that we split the work using the binary representation of the exponent.
Let's write n in base 2, for example: 313=311012=38×34×31
Since the number n has exactly ⌊logN⌋+1 digits in base 2, we only need to perform O(logN)multiplications, if we know the powers a1,a2,a4,...alog(N).
So we only need to know a fast way to compute those. Luckily this is very easy, since an element in the sequence is just the square of the previous element.
So to get the final answer for 313, we only need to multiply three of them (skipping 32 because the corresponding bit in n is not set): 313= 6561⋅81⋅3 = 1594323
The final complexity of this algorithm is O(logn): we have to compute logn powers of a, and then have to do at most logn multiplications to get the final answer from them.
The following recursive approach expresses the same idea:
an=⎩⎪⎪⎪⎨⎪⎪⎪⎧1(a2n)2(a2n−1)2⋅aif n==0if n>0 and n evenif n>0 and n odd
Implementation
// binpow(a, b) => a^b
long long binpow(long long a, long long b)
{
if (b == 0)
return 1;
long long res = binpow(a, b / 2);
if (b % 2)
return res * res * a;
else
return res * res;
}
long long binpow(long long a, long long b) {
long long res = 1;
while (b > 0) {
if (b & 1)
res = res * a;
a = a * a;
b >>= 1;
}
return res;
}