Competitive Coding
Unit 2: Primality Testing
From naive checks to blazing-fast sieves โ master every primality testing algorithm, crack competitive coding problems, and understand the cryptography that secures India's digital payments.
โฑ๏ธ 6 hrs theory + 4 hrs practice | ๐ฐ Earning Potential: โน5,000โโน25,000/month | ๐ 30 MCQs (Bloom's Mapped)
๐ผ Jobs this unlocks: Cryptography Engineer (โน8โ15 LPA) | Security Developer (โน6โ12 LPA) | Competitive Programmer
Opening Hook โ The Invisible Math Guarding Your Money
๐ Every UPI Payment You Make is Secured by Prime Numbers
Open PhonePe or Google Pay right now. Send โน1 to a friend. In that fraction of a second, your phone performed RSA encryption โ a cryptographic algorithm that relies entirely on the difficulty of factoring the product of two very large prime numbers (each 300+ digits long).
India's UPI processed 13.89 billion transactions worth โน20.64 lakh crore in May 2024 alone. Every single one of those transactions was secured by primality testing. The NPCI (National Payments Corporation of India) uses TLS certificates backed by RSA-2048, which depends on 617-digit prime numbers. If someone could efficiently test and factor these primes, they could intercept every payment on PhonePe, Google Pay, Paytm, and BHIM.
What if YOU understood how this works? What if you could implement the same algorithms that protect billions of rupees? That's exactly what this chapter teaches you โ from the simplest O(n) check to the blazing-fast Sieve of Eratosthenes used in competitive programming.
Learning Outcomes โ Bloom's Taxonomy Mapped
| Bloom's Level | Learning Outcome |
|---|---|
| ๐ต Remember | Define prime numbers and list their fundamental properties (infinitude, distribution, fundamental theorem of arithmetic) |
| ๐ต Remember | State Fermat's Little Theorem and recall the first 25 prime numbers |
| ๐ข Understand | Explain why checking divisibility only up to โn is sufficient for primality testing, with mathematical proof |
| ๐ข Understand | Describe the Sieve of Eratosthenes algorithm step-by-step and trace it for any given n |
| ๐ก Apply | Implement the O(โn) primality test in both C++ and Python with edge-case handling |
| ๐ก Apply | Code the Sieve of Eratosthenes to generate all primes up to N = 10โท |
| ๐ Analyze | Compare time complexities of naive O(n), O(โn), Fermat, and Sieve methods for different input ranges |
| ๐ Analyze | Analyze why Carmichael numbers are problematic for the Fermat primality test and identify examples |
| ๐ด Evaluate | Assess when to use deterministic vs probabilistic primality tests based on problem constraints |
| ๐ด Evaluate | Evaluate Sieve of Eratosthenes vs Segmented Sieve trade-offs for different memory and range requirements |
| ๐ฃ Create | Design a comprehensive prime-testing library that combines multiple algorithms with automatic method selection |
| ๐ฃ Create | Build a segmented sieve for arbitrary range [L, R] queries where R can be up to 10โน |
Concept Explanation โ Primality Testing from Scratch
1. Introduction to Primality Testing
What is a prime number? A prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself. The first few primes are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47.
Note that 2 is the only even prime. Every even number greater than 2 is divisible by 2, so it cannot be prime. Also, 1 is NOT prime by convention (it has only one divisor, not two).
๐ข Why Do Primes Matter?
1. Cryptography (RSA): RSA encryption relies on the product of two large primes. Multiplying them is easy (milliseconds), but factoring the result takes billions of years. This asymmetry secures all online banking, UPI payments, and HTTPS websites.
2. Hash Tables: Using prime numbers as hash table sizes reduces collisions. Languages like Java use prime-based hash functions internally.
3. Competitive Programming: Primality testing appears in 20%+ of competitive coding problems. Platforms like Codeforces, CodeChef, and LeetCode regularly feature prime-based problems.
4. Random Number Generation: Many pseudorandom number generators (PRNGs) use prime moduli for better distribution.
Naive O(n) Primality Test
The simplest approach: check if any number from 2 to n-1 divides n. If yes, n is not prime.
C++ // Naive primality test โ O(n) time complexity #include <iostream> using namespace std; bool isPrime(int n) { if (n <= 1) return false; for (int i = 2; i < n; i++) { if (n % i == 0) return false; } return true; } int main() { int n; cout << "Enter a number: "; cin >> n; if (isPrime(n)) cout << n << " is PRIME" << endl; else cout << n << " is NOT prime" << endl; return 0; }
Python # Naive primality test โ O(n) time complexity def is_prime(n): if n <= 1: return False for i in range(2, n): if n % i == 0: return False return True n = int(input("Enter a number: ")) if is_prime(n): print(f"{n} is PRIME") else: print(f"{n} is NOT prime")
2. O(โn) Optimized Primality Test
Key Insight: If n = a ร b where both a and b are greater than โn, then a ร b > โn ร โn = n, which is a contradiction. Therefore, if n has any factor other than 1 and itself, at least one factor must be โค โn.
๐ Mathematical Proof: Why โn is Sufficient
Theorem: If n is composite, then n has a prime factor p where p โค โn.
Proof: Let n be composite. Then n = a ร b where 1 < a โค b < n. Since a โค b, we have a ร a โค a ร b = n, therefore a โค โn. Since a > 1 and a divides n, a has a prime factor p that also divides n, and p โค a โค โn. โ
Practical impact: For n = 10โน, instead of checking 10โน divisors, we check only โ(10โน) โ 31,623 divisors. That's a 31,600ร speedup!
C++ // O(โn) primality test โ optimized #include <iostream> #include <cmath> using namespace std; bool isPrime(int n) { if (n <= 1) return false; if (n <= 3) return true; if (n % 2 == 0 || n % 3 == 0) return false; for (int i = 5; i * i <= n; i += 6) { if (n % i == 0 || n % (i + 2) == 0) return false; } return true; } int main() { int n; cout << "Enter number: "; cin >> n; cout << n << (isPrime(n) ? " is PRIME" : " is NOT prime") << endl; return 0; }
Python # O(โn) primality test โ optimized with 6kยฑ1 trick def is_prime(n): if n <= 1: return False if n <= 3: return True if n % 2 == 0 or n % 3 == 0: return False i = 5 while i * i <= n: if n % i == 0 or n % (i + 2) == 0: return False i += 6 return True
3. Factorization of a Number
Trial division finds all prime factors by repeatedly dividing by the smallest possible factor. The optimized approach runs in O(โn) time.
C++ // Find ALL prime factors of n โ O(โn) #include <iostream> #include <vector> using namespace std; vector<int> primeFactors(int n) { vector<int> factors; while (n % 2 == 0) { factors.push_back(2); n /= 2; } for (int i = 3; i * i <= n; i += 2) { while (n % i == 0) { factors.push_back(i); n /= i; } } if (n > 1) factors.push_back(n); return factors; } int main() { int n = 84; auto f = primeFactors(n); cout << "Prime factors of " << n << ": "; for (int x : f) cout << x << " "; return 0; }
Python # Find ALL prime factors of n โ O(โn) def prime_factors(n): factors = [] while n % 2 == 0: factors.append(2) n //= 2 i = 3 while i * i <= n: while n % i == 0: factors.append(i) n //= i i += 2 if n > 1: factors.append(n) return factors print(prime_factors(84)) # [2, 2, 3, 7]
4. Finding Prime Factors by Taking Square Root
๐ Worked Example: n = 84
Step 1: 84 รท 2 = 42 โ Factor found: 2
Step 2: 42 รท 2 = 21 โ Factor found: 2
Step 3: 21 รท 3 = 7 โ Factor found: 3
Step 4: 7 > 1 and โ7 โ 2.6 < 3 (next candidate), so 7 is prime โ Factor found: 7
Result: 84 = 2ยฒ ร 3ยน ร 7ยน
5. Fermat Primality Test
๐ฌ Fermat's Little Theorem
Statement: If p is a prime number and a is any integer not divisible by p, then:
apโ1 โก 1 (mod p)
Example: Let p = 7, a = 2. Then 2โถ = 64. And 64 mod 7 = 1. โ Confirmed!
Contrapositive: If anโ1 โข 1 (mod n), then n is definitely composite.
The Test: Pick random values of a. If any gives anโ1 โข 1 (mod n), n is composite. If all pass, n is probably prime.
C++ // Fermat Primality Test โ Probabilistic #include <iostream> #include <cstdlib> using namespace std; long long power(long long base, long long exp, long long mod) { long long result = 1; base %= mod; while (exp > 0) { if (exp % 2 == 1) result = (result * base) % mod; exp /= 2; base = (base * base) % mod; } return result; } bool fermatTest(int n, int k) { if (n <= 1) return false; if (n <= 3) return true; for (int i = 0; i < k; i++) { int a = 2 + rand() % (n - 3); if (power(a, n - 1, n) != 1) return false; } return true; }
Python # Fermat Primality Test โ Probabilistic import random def fermat_test(n, k=10): if n <= 1: return False if n <= 3: return True for _ in range(k): a = random.randint(2, n - 2) if pow(a, n - 1, n) != 1: return False return True print(fermat_test(7)) # True print(fermat_test(561)) # True! (FALSE POSITIVE โ Carmichael number) print(fermat_test(15)) # False
6. Sieve of Eratosthenes โญ MOST IMPORTANT
The Sieve of Eratosthenes is the single most important algorithm in this entire unit. It generates ALL prime numbers up to n in O(n log log n) time. If you learn only one thing from this chapter, learn this.
๐ Algorithm Step-by-Step
Step 1: Create a boolean array is_prime[0..n], initialized to true.
Step 2: Mark is_prime[0] and is_prime[1] as false (not prime).
Step 3: Start with p = 2 (first prime).
Step 4: Mark all multiples of p (starting from pยฒ) as false.
Step 5: Find the next unmarked number โ that's the next prime.
Step 6: Repeat until pยฒ > n.
Step 7: All remaining true entries are primes!
ASCII Visualization: Sieve for n = 30
| Step | Numbers 2โ30 (โ = prime candidate, โ = crossed out) |
|---|---|
| Initial | โ2 โ3 โ4 โ5 โ6 โ7 โ8 โ9 โ10 โ11 โ12 โ13 โ14 โ15 โ16 โ17 โ18 โ19 โ20 โ21 โ22 โ23 โ24 โ25 โ26 โ27 โ28 โ29 โ30 |
| p=2 Cross 4,6,8โฆ30 | โ2 โ3 โ4 โ5 โ6 โ7 โ8 โ9 โ10 โ11 โ12 โ13 โ14 โ15 โ16 โ17 โ18 โ19 โ20 โ21 โ22 โ23 โ24 โ25 โ26 โ27 โ28 โ29 โ30 |
| p=3 Cross 9,15,21,27 | โ2 โ3 โ4 โ5 โ6 โ7 โ8 โ9 โ10 โ11 โ12 โ13 โ14 โ15 โ16 โ17 โ18 โ19 โ20 โ21 โ22 โ23 โ24 โ25 โ26 โ27 โ28 โ29 โ30 |
| p=5 Cross 25 | โ2 โ3 โ4 โ5 โ6 โ7 โ8 โ9 โ10 โ11 โ12 โ13 โ14 โ15 โ16 โ17 โ18 โ19 โ20 โ21 โ22 โ23 โ24 โ25 โ26 โ27 โ28 โ29 โ30 |
| Done! โ30 โ 5.47 | Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 (10 primes found) |
C++ // Sieve of Eratosthenes โ O(n log log n) #include <iostream> #include <vector> using namespace std; vector<int> sieve(int n) { vector<bool> is_prime(n + 1, true); is_prime[0] = is_prime[1] = false; for (int p = 2; p * p <= n; p++) { if (is_prime[p]) { for (int j = p * p; j <= n; j += p) is_prime[j] = false; } } vector<int> primes; for (int i = 2; i <= n; i++) if (is_prime[i]) primes.push_back(i); return primes; } int main() { auto primes = sieve(30); cout << "Primes up to 30: "; for (int p : primes) cout << p << " "; return 0; }
Python # Sieve of Eratosthenes โ O(n log log n) def sieve(n): is_prime = [True] * (n + 1) is_prime[0] = is_prime[1] = False p = 2 while p * p <= n: if is_prime[p]: for j in range(p * p, n + 1, p): is_prime[j] = False p += 1 return [i for i in range(2, n + 1) if is_prime[i]] print(sieve(30)) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
โฑ๏ธ Time Complexity: O(n log log n)
The total work done is: n/2 + n/3 + n/5 + n/7 + n/11 + ... (sum over all primes p โค n).
This equals n ร ฮฃ(1/p) for primes p โค n. By Mertens' theorem, this sum โ log(log n).
So total operations โ O(n log log n). For n = 10โท, log log n โ 3, so it's essentially O(3n) โ nearly linear!
Space complexity: O(n) for the boolean array.
7. Segmented Sieve
When n is very large (say 10โน), a regular sieve needs a boolean array of 10โน entries โ about 1 GB of RAM. Most competitive programming judges allow only 256 MB. Solution: segmented sieve.
๐ง How Segmented Sieve Works
Step 1: Generate all primes up to โR using the regular sieve (these "small primes" fit easily in memory).
Step 2: Divide the range [L, R] into segments of size ~โR.
Step 3: For each segment, use the small primes to mark composites.
Step 4: Collect unmarked numbers โ those are primes in the range.
Memory: O(โR) instead of O(R). For R = 10โน, that's ~31,623 instead of 10โน!
C++ // Segmented Sieve โ find primes in range [L, R] #include <iostream> #include <vector> #include <cmath> using namespace std; vector<long long> segmentedSieve(long long L, long long R) { int limit = (int)sqrt((double)R) + 1; vector<bool> mark(limit + 1, true); vector<int> small_primes; for (int p = 2; p <= limit; p++) { if (mark[p]) { small_primes.push_back(p); for (int j = p * p; j <= limit; j += p) mark[j] = false; } } vector<bool> is_prime(R - L + 1, true); for (int p : small_primes) { long long start = max((long long)p * p, ((L + p - 1) / p) * p); for (long long j = start; j <= R; j += p) is_prime[j - L] = false; } if (L == 1) is_prime[0] = false; vector<long long> result; for (long long i = 0; i <= R - L; i++) if (is_prime[i]) result.push_back(L + i); return result; }
Python # Segmented Sieve โ find primes in [L, R] import math def segmented_sieve(L, R): limit = int(math.sqrt(R)) + 1 # Step 1: small primes via regular sieve mark = [True] * (limit + 1) small_primes = [] for p in range(2, limit + 1): if mark[p]: small_primes.append(p) for j in range(p*p, limit+1, p): mark[j] = False # Step 2: sieve the range [L, R] is_prime = [True] * (R - L + 1) for p in small_primes: start = max(p * p, ((L + p - 1) // p) * p) for j in range(start, R + 1, p): is_prime[j - L] = False if L == 1: is_prime[0] = False return [L + i for i in range(R - L + 1) if is_prime[i]] print(segmented_sieve(100, 150)) # [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
8. Sieve of Atkins
The Sieve of Atkins is a modern algorithm that uses quadratic forms and modular arithmetic. It has a theoretical time complexity of O(n / log log n), slightly better than Eratosthenes for very large n.
๐ฌ Three Quadratic Forms
The algorithm toggles entries based on solutions to three equations:
Form 1: 4xยฒ + yยฒ โก 1 (mod 4) โ for n โก 1 (mod 4)
Form 2: 3xยฒ + yยฒ โก 7 (mod 12) โ for n โก 7 (mod 12)
Form 3: 3xยฒ โ yยฒ (where x > y) โก 11 (mod 12) โ for n โก 11 (mod 12)
After toggling, eliminate all multiples of squares of primes.
When to use: Only for very large n (> 10โธ) where the constant factor improvement matters. For most competitive programming, Eratosthenes is preferred due to simplicity.
C++ // Sieve of Atkins โ Overview Implementation #include <iostream> #include <vector> #include <cmath> using namespace std; vector<int> sieveOfAtkins(int limit) { vector<bool> sieve(limit + 1, false); if (limit > 2) sieve[2] = true; if (limit > 3) sieve[3] = true; for (int x = 1; x * x <= limit; x++) { for (int y = 1; y * y <= limit; y++) { int n = 4 * x * x + y * y; if (n <= limit && (n % 12 == 1 || n % 12 == 5)) sieve[n] = !sieve[n]; n = 3 * x * x + y * y; if (n <= limit && n % 12 == 7) sieve[n] = !sieve[n]; n = 3 * x * x - y * y; if (x > y && n <= limit && n % 12 == 11) sieve[n] = !sieve[n]; } } for (int r = 5; r * r <= limit; r++) if (sieve[r]) for (int i = r * r; i <= limit; i += r * r) sieve[i] = false; vector<int> primes; for (int i = 2; i <= limit; i++) if (sieve[i]) primes.push_back(i); return primes; }
9. Mansi and Her Series
Problem: Given N, generate first N terms of a series where: if index i is prime, term[i] = i; otherwise, term[i] = smallest prime factor of i.
C++ // Mansi's Series using Smallest Prime Factor (SPF) sieve #include <iostream> #include <vector> using namespace std; int main() { int N = 10; vector<int> spf(N + 1); for (int i = 0; i <= N; i++) spf[i] = i; for (int i = 2; i * i <= N; i++) { if (spf[i] == i) { for (int j = i * i; j <= N; j += i) if (spf[j] == j) spf[j] = i; } } cout << "Mansi's Series: "; for (int i = 1; i <= N; i++) cout << spf[i] << " "; return 0; }
10. Collections of Pens
Problem: Rohan has N pens. He wants to distribute them equally among groups. Find the total number of ways (= number of divisors of N).
C++ // Count divisors using prime factorization #include <iostream> using namespace std; int countDivisors(int n) { int count = 1; for (int i = 2; i * i <= n; i++) { int exp = 0; while (n % i == 0) { exp++; n /= i; } count *= (exp + 1); } if (n > 1) count *= 2; return count; } int main() { int n = 12; cout << "N = " << n << ", Ways = " << countDivisors(n) << endl; // 12 = 2^2 ร 3^1 โ (2+1)(1+1) = 6 return 0; }
11. Next Prime Palindrome
C++ // Find next number that is both prime AND palindrome #include <iostream> #include <string> #include <algorithm> using namespace std; bool isPrime(int n) { if (n <= 1) return false; if (n <= 3) return true; if (n % 2 == 0 || n % 3 == 0) return false; for (int i = 5; i * i <= n; i += 6) if (n % i == 0 || n % (i+2) == 0) return false; return true; } bool isPalindrome(int n) { string s = to_string(n); string r = s; reverse(r.begin(), r.end()); return s == r; } int nextPrimePalindrome(int n) { int candidate = n + 1; while (true) { if (isPalindrome(candidate) && isPrime(candidate)) return candidate; candidate++; } } int main() { cout << "Next prime palindrome after 100: " << nextPrimePalindrome(100) << endl; cout << "Next prime palindrome after 7: " << nextPrimePalindrome(7) << endl; return 0; }
Learn by Doing โ 3-Tier Lab Structure
๐ข Tier 1 โ GUIDED: Implement O(โn) Primality Test
Step 1: Handle edge cases
n โค 1 โ not prime. n = 2 or n = 3 โ prime.
Step 2: Check divisibility by 2 and 3
If n % 2 == 0 or n % 3 == 0 โ not prime.
Step 3: Check 6kยฑ1 up to โn
Loop i from 5, step 6. Check n % i and n % (i+2).
Step 4: Test with these inputs
Test: 1, 2, 3, 4, 17, 25, 97, 100, 7919, 1000000007
๐ก Tier 2 โ SEMI-GUIDED: Sieve of Eratosthenes
Your Mission:
Generate all primes up to 10โถ and count them.
Hints:
- Create a boolean array of size 10โถ + 1, initialized to true
- Mark 0 and 1 as false
- For each p from 2 where pยฒ โค n, mark multiples from pยฒ as false
- Count and collect all remaining true entries
๐ด Tier 3 โ OPEN CHALLENGE: Segmented Sieve for [L, R]
The Brief:
Given L and R (up to 10โน, R โ L โค 10โถ), find and print all primes in the range [L, R]. Your solution must use O(โR) memory.
Test case: L=999999000000, R=1000000000000. How many primes are in this range?
Problem Set โ Practice Questions
Tracing Questions (5)
T1. Trace the Sieve of Eratosthenes for n = 20. Show the array state after each prime's multiples are crossed out.
T2. Trace the O(โn) algorithm for n = 97. List each divisor checked and the final result.
T3. Trace the Fermat test for n = 561 with bases a = 2, 3, 5. Show each computation a^(n-1) mod n.
T4. Trace the prime factorization of n = 360. Show each division step.
T5. Trace the segmented sieve for the range [10, 30] using small primes {2, 3, 5}.
Programming Problems (8)
P1. Count the number of primes up to N. Input: N = 10โถ. Expected output: 78498.
P2. Find the Nth prime number. Input: N = 10001. Expected output: 104743.
P3. Check if a number is a Mersenne prime (of the form 2แต โ 1). Test for p = 2, 3, 5, 7, 11, 13.
P4. Find all prime factors of N and print in exponential form. Input: 360 โ Output: 2ยณ ร 3ยฒ ร 5ยน.
P5. Generate all twin primes up to N. Twin primes: (3,5), (5,7), (11,13), (17,19), ...
P6. Find the largest prime factor of N. Input: 600851475143. (This is Project Euler Problem 3!)
P7. Count prime palindromes up to N. Input: N = 1000. Expected output: 5 (2, 3, 5, 7, 11).
P8. Sum of all primes up to N using Sieve. Input: N = 2ร10โถ. Verify your answer.
Industry Application Problems (3)
I1. RSA Key Generation: Given primes p = 61, q = 53, compute n = pรq, ฯ(n) = (p-1)(q-1), find e coprime to ฯ(n), compute d = eโปยน mod ฯ(n). Encrypt and decrypt the message m = 65.
I2. Hash Table Sizing: Write a function that, given N (desired table size), returns the smallest prime โฅ N. This is used in languages like C++ (unordered_map) and Java (HashMap) internally.
I3. Checksum Verification: Implement a prime-based rolling hash for a string. Use a prime modulus (10โน + 7) and prime base (31). Verify string integrity after transmission.
Interview Questions (3)
Q1. (Google-style): Given an array of N numbers (each โค 10โถ), count how many are prime. Optimize using sieve preprocessing.
Q2. (Amazon-style): Find the k-th prime number efficiently. Can you do better than checking each number?
Q3. (Microsoft-style): Given array A of N integers, count pairs (i, j) where i < j and A[i] + A[j] is prime. Optimize using Goldbach-related observations.
MCQ Assessment Bank โ 30 Questions (Bloom's Mapped)
Remember / Identify (Q1โQ5)
Which of the following is a prime number?
- 51
- 67
- 91
- 87
What is the only even prime number?
- 1
- 2
- 4
- 0
Fermat's Little Theorem states that if p is prime, then a^(p-1) mod p equals:
- 0
- 1
- p-1
- a
The time complexity of the Sieve of Eratosthenes is:
- O(nยฒ)
- O(n log n)
- O(n log log n)
- O(nโn)
Which of these is a Carmichael number?
- 511
- 561
- 571
- 581
Understand / Explain (Q6โQ10)
Why is checking divisors only up to โn sufficient for primality testing?
- All prime factors are less than โn
- If n has a factor greater than โn, it must have a corresponding factor less than โn
- โn is always a prime number
- It reduces memory usage
Why does the Sieve of Eratosthenes start marking from pยฒ instead of 2p?
- To save memory
- Because all smaller multiples of p have already been marked by smaller primes
- pยฒ is always composite
- It's an arbitrary optimization
Why is the Fermat test called "probabilistic"?
- It uses random number generation internally
- It can give false positives (declare composite numbers as prime)
- It runs in random time
- It only works for random inputs
What is the main advantage of a segmented sieve over a regular sieve?
- It is faster
- It uses significantly less memory
- It finds more primes
- It works with negative numbers
In the context of RSA encryption, why are large primes essential?
- Large primes make the key look impressive
- The security depends on the difficulty of factoring the product of two large primes
- Small primes cannot be multiplied
- Large primes are faster to compute with
Apply (Q11โQ15)
What is the output of the Sieve of Eratosthenes for n = 10?
- 2, 3, 5, 7, 9
- 2, 3, 5, 7
- 1, 2, 3, 5, 7
- 2, 4, 6, 8, 10
The prime factorization of 360 is:
- 2ยณ ร 3ยฒ ร 5
- 2ยฒ ร 3ยณ ร 5
- 2ยณ ร 3 ร 5ยฒ
- 4 ร 9 ร 10
How many prime numbers are between 1 and 30?
- 8
- 10
- 11
- 12
For Fermat test with n=7 and a=3, what is 3^6 mod 7?
- 0
- 1
- 3
- 6
What is the next prime palindrome after 10?
- 11
- 13
- 22
- 101
Analyze (Q16โQ20)
For checking if a single number n is prime, which method is most efficient?
- Sieve of Eratosthenes
- O(โn) trial division
- Naive O(n) check
- Segmented sieve
Why is 1729 special in number theory?
- It is the largest known prime
- It is both a Carmichael number and the Hardy-Ramanujan number
- It is the only number divisible by all single-digit primes
- It is the sum of all primes up to 100
What happens if we use the Sieve of Eratosthenes for n = 10โน?
- It works perfectly
- It runs out of memory (needs ~1 GB for boolean array)
- It produces wrong results
- It takes exactly 1 second
Compare the number of operations for O(โn) vs Sieve for finding all primes up to n = 10โถ:
- โn is faster for this task
- Sieve is faster because it processes all numbers at once with O(n log log n)
- They take the same time
- Neither can handle 10โถ
Which data structure is used internally by the Sieve of Eratosthenes?
- Linked list
- Binary search tree
- Boolean array
- Hash map
Evaluate (Q21โQ25)
For a competitive coding problem asking "Is N prime?" where N โค 10ยนโธ, which method is best?
- Sieve of Eratosthenes
- Naive O(n) check
- Miller-Rabin probabilistic test
- Segmented sieve
When should you use Sieve of Atkins instead of Eratosthenes?
- Always โ it is strictly better
- Never โ Eratosthenes is always better
- Only for very large n (>10โธ) where the slight theoretical advantage matters
- Only for small n (<100)
A student claims "If a number passes the Fermat test with 100 random bases, it is definitely prime." Is this correct?
- Yes, 100 bases is more than enough
- No, Carmichael numbers pass for all coprime bases, so even 100 tests cannot guarantee primality
- Yes, but only for odd numbers
- No, the Fermat test never works
For finding primes in range [10โน, 10โน+10โถ], the best approach is:
- Regular Sieve up to 10โน
- Check each number with O(โn)
- Segmented Sieve
- Fermat test on each number
Which property makes prime numbers useful for hash table sizes?
- Prime numbers are always odd
- Using a prime modulus distributes hash values more uniformly, reducing collisions
- Prime numbers are faster to compute
- Prime numbers use less memory
Create / Design (Q26โQ30)
To build a function that checks primality for multiple queries where each n โค 10โท, the best preprocessing is:
- No preprocessing; check each query with O(โn)
- Precompute a sieve up to 10โท and answer each query in O(1)
- Store all primes in a hash set
- Use Fermat test for each query
To count divisors of N efficiently, the best approach combines:
- Checking all numbers from 1 to N
- Prime factorization + divisor count formula: product of (exponent+1)
- Using Sieve of Eratosthenes
- Binary search
To generate the Smallest Prime Factor (SPF) for all numbers up to N, you should modify the sieve to:
- Store the first prime that marks each composite number
- Count how many times each number is marked
- Use a linked list instead of an array
- Run the sieve backwards
To design an efficient "next prime" function, the best strategy for large N (>10โถ) is:
- Increment N and test each with O(โn) until a prime is found
- Use the Prime Number Theorem to jump approximately ln(N) ahead, then search
- Generate all primes up to 2N with a sieve
- Use Fermat test only
To implement a secure random prime generator for a simplified RSA system, you need:
- Any random odd number
- A random number generator + Miller-Rabin test with sufficient iterations
- The largest known Mersenne prime
- Sequential search starting from 2
Short Answer Questions (8)
Q1. Define primality testing and explain its importance in computer science.
Primality testing is the process of determining whether a given natural number is prime (divisible only by 1 and itself). It is fundamental to computer science for several reasons: (1) Cryptography โ RSA encryption, which secures all online transactions including UPI payments, relies on large primes. (2) Hash tables โ prime-sized tables reduce collisions. (3) Random number generation โ many PRNGs use prime moduli. (4) Competitive programming โ primality problems appear frequently on Codeforces, CodeChef, and LeetCode. (5) Error-correcting codes โ Reed-Solomon codes use prime field arithmetic. Understanding efficient primality testing is essential for any serious programmer or computer scientist.
Q2. Why is checking divisibility up to โn sufficient? Prove it.
Proof: Suppose n is composite, meaning n = a ร b where 1 < a, b < n. Assume for contradiction that both a > โn and b > โn. Then a ร b > โn ร โn = n, contradicting n = a ร b. Therefore, at least one of a or b must be โค โn. Since any composite number n has at least one factor โค โn, we only need to check potential divisors from 2 to โn. If none divides n, then n must be prime. Impact: For n = 10โน, this reduces checks from ~10โน to ~31,623 โ a speedup of over 31,000ร.
Q3. Explain Fermat's Little Theorem with an example.
Fermat's Little Theorem: If p is a prime number and a is any integer with gcd(a, p) = 1, then a^(pโ1) โก 1 (mod p). Example: Let p = 7 and a = 2. Compute 2^(7โ1) = 2โถ = 64. Now 64 mod 7 = 64 โ 63 = 1. Since the result is 1, the theorem holds. โ Another example: p = 11, a = 3. 3ยนโฐ = 59049. 59049 mod 11 = 59049 โ 5368ร11 = 59049 โ 59048 = 1. โ The contrapositive is used for testing: if a^(nโ1) mod n โ 1, then n is definitely composite.
Q4. What are Carmichael numbers? Give 3 examples.
Carmichael numbers are composite numbers that satisfy Fermat's Little Theorem for ALL bases coprime to them. They are "Fermat liars" โ they fool the Fermat primality test into thinking they are prime. Examples: (1) 561 = 3 ร 11 ร 17 โ the smallest Carmichael number. (2) 1105 = 5 ร 13 ร 17. (3) 1729 = 7 ร 13 ร 19 โ also the famous Hardy-Ramanujan number. They are problematic because no matter how many random bases you test with Fermat's method, these numbers will always pass. To handle them, use the Miller-Rabin test, which can detect Carmichael numbers.
Q5. Describe the Sieve of Eratosthenes step-by-step for n = 30.
Step 1: Create boolean array [0..30], all set to true. Set arr[0] = arr[1] = false. Step 2 (p=2): Mark multiples 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 as false. Step 3 (p=3): Mark 9, 15, 21, 27 as false (6, 12, 18, 24, 30 already marked). Step 4 (p=5): Mark 25 as false (other multiples already marked). Step 5: Since 6ยฒ = 36 > 30, we stop. Result: Numbers still marked true: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 โ these are all 10 primes โค 30.
Q6. Compare time complexity of naive primality test vs Sieve.
Naive test: O(n) per number or O(โn) per number with optimization. To check ALL numbers up to N: N ร O(โN) = O(NโN). Sieve of Eratosthenes: O(N log log N) for ALL numbers up to N simultaneously. Comparison: For N = 10โถ: Naive = 10โถ ร 10ยณ = 10โน operations. Sieve = 10โถ ร 3 โ 3ร10โถ operations. The sieve is ~333ร faster. When to use each: For a single query, โn test is better. For multiple queries or generating all primes up to N, the sieve is vastly superior.
Q7. What is a segmented sieve and when to use it?
A segmented sieve divides the range [L, R] into smaller segments of size ~โR and sieves each segment independently using pre-computed small primes (up to โR). Memory: O(โR) instead of O(R). When to use: When R > 10โท (regular sieve exceeds memory limits). For R = 10โน, regular sieve needs ~1 GB; segmented sieve needs only ~31 KB for small primes plus segment buffer. Use cases: Finding primes in a range [L, R], prime counting in large ranges, problems on SPOJ like PRIME1. Time complexity remains O((RโL+1) log log R + โR).
Q8. Difference between deterministic and probabilistic primality tests.
Deterministic tests (trial division, AKS) give a definitive yes/no answer. Trial division is O(โn) and always correct. AKS runs in polynomial time and is always correct but has large constants. Probabilistic tests (Fermat, Miller-Rabin) are faster but can produce false positives. Fermat can be fooled by Carmichael numbers. Miller-Rabin with k iterations has error probability < 4^(โk) โ with k=40, the probability of error is less than 2^(โ80), which is negligible. For competitive coding: Deterministic O(โn) for n โค 10ยนยฒ, Miller-Rabin for n > 10ยนยฒ.
Long Answer Questions (3)
Q1. Compare all primality testing methods covered in this unit.
| Method | Time | Space | Type | Best Use |
|---|---|---|---|---|
| Naive O(n) | O(n) | O(1) | Deterministic | Educational only |
| O(โn) | O(โn) | O(1) | Deterministic | Single query, n โค 10ยนยฒ |
| Fermat | O(k log n) | O(1) | Probabilistic | Quick check (beware Carmichael) |
| Miller-Rabin | O(k logยฒ n) | O(1) | Probabilistic | Single query, n โค 10ยนโธ |
| Sieve | O(n log log n) | O(n) | Deterministic | All primes up to n โค 10โท |
| Segmented Sieve | O((R-L)ยทlog log R) | O(โR) | Deterministic | Range queries, R up to 10โน |
| Sieve of Atkins | O(n/log log n) | O(n) | Deterministic | Theoretical; very large n |
The choice depends on the problem: single query vs multiple queries, range of n, memory constraints, and whether deterministic answers are required. For most competitive programming, O(โn) for single queries and Sieve of Eratosthenes for bulk generation cover 95% of problems.
Q2. Explain the Sieve of Eratosthenes in complete detail.
The Sieve of Eratosthenes, invented by the Greek mathematician Eratosthenes around 240 BC, is an algorithm to find all prime numbers up to a given limit n. It works by iteratively marking the multiples of each prime starting from 2.
Mathematical Basis: The Fundamental Theorem of Arithmetic states every integer > 1 has a unique prime factorization. The sieve exploits the fact that any composite number must have a prime factor โค โn.
Optimization โ start from pยฒ: When processing prime p, we start marking from pยฒ (not 2p) because all smaller multiples kp where k < p have already been marked by the prime factor k. This reduces the total work significantly.
Time Complexity Analysis: The inner loop for prime p does n/p operations. Total work = ฮฃ(n/p) for all primes p โค โn = n ร ฮฃ(1/p). By Mertens' theorem, ฮฃ(1/p) for primes p โค n โ log log n. Therefore, total time = O(n log log n). Since log log n grows extremely slowly (log log 10โน โ 3), this is practically linear.
Optimizations: (1) Bitwise sieve: use bits instead of bytes, reducing memory by 8ร. (2) Wheel factorization: skip multiples of 2, 3, 5 automatically. (3) Segment the sieve for cache efficiency.
Q3. How are prime numbers used in RSA encryption?
RSA Key Generation Process:
1. Choose two large primes p and q (each 300+ digits in practice).
2. Compute n = p ร q. This is the modulus. n is made public; p and q are kept secret.
3. Compute Euler's totient: ฯ(n) = (pโ1)(qโ1). This is kept secret.
4. Choose public exponent e such that 1 < e < ฯ(n) and gcd(e, ฯ(n)) = 1. Commonly e = 65537.
5. Compute private exponent d = eโปยน mod ฯ(n) using the Extended Euclidean Algorithm.
6. Public key: (n, e). Private key: (n, d).
Encryption: c = m^e mod n. Decryption: m = c^d mod n.
Why large primes are essential: The security relies on the computational difficulty of factoring n back into p and q. For RSA-2048, n has 617 digits. The best known factoring algorithms (General Number Field Sieve) would take billions of years with current computing power.
Indian Context: India's UPI (Unified Payments Interface), managed by NPCI, processes 10+ billion transactions monthly. Every transaction uses TLS (Transport Layer Security) which relies on RSA or ECDSA for key exchange. Aadhaar authentication also uses RSA-2048 for securing biometric data transmission. The security of โน20+ lakh crore in monthly digital payments rests on the difficulty of factoring large primes.
Lab Programs from Syllabus (5)
Lab 1: Finding Prime Factors by Square Root Method
Objective:
Find all prime factors of a number using trial division up to โn.
Algorithm:
- While n is divisible by 2, print 2 and divide n by 2.
- For odd i from 3 to โn: while n is divisible by i, print i and divide.
- If n > 1, print n (it's a remaining prime factor).
C++ #include <iostream> #include <cmath> using namespace std; void primeFactors(int n) { while (n % 2 == 0) { cout << 2 << " "; n /= 2; } for (int i=3; i*i<=n; i+=2) { while (n%i==0) { cout<<i<<" "; n/=i; } } if (n>1) cout<<n; cout<<endl; } int main() { primeFactors(84); return 0; }
Viva Voce:
V1: What is prime factorization? โ Expressing a number as a product of prime powers.
V2: Why check up to โn? โ If n has a factor > โn, it must have a corresponding factor < โn.
V3: Time complexity? โ O(โn).
V4: Can this handle very large numbers? โ Up to ~10โน efficiently; beyond that, use Pollard's rho.
V5: State the Fundamental Theorem of Arithmetic. โ Every integer > 1 has a unique prime factorization.
Lab 2: Fermat Primality Test
Objective:
Implement probabilistic primality test using Fermat's Little Theorem.
Python import random def power_mod(base, exp, mod): result = 1 base %= mod while exp > 0: if exp % 2 == 1: result = (result * base) % mod exp //= 2 base = (base * base) % mod return result def fermat_test(n, k=10): if n < 2: return False if n < 4: return True for _ in range(k): a = random.randint(2, n-2) if power_mod(a, n-1, n) != 1: return False return True for n in [7, 15, 561, 997]: print(f"{n}: {'Prime' if fermat_test(n) else 'Composite'}")
Viva Voce:
V1: State Fermat's Little Theorem. โ If p is prime and gcd(a,p)=1, then a^(p-1) โก 1 (mod p).
V2: What are Carmichael numbers? โ Composites that pass Fermat test for all coprime bases (e.g., 561).
V3: Why multiple iterations? โ Each iteration with a random base reduces false positive probability.
V4: What is modular exponentiation? โ Computing a^b mod m in O(log b) using repeated squaring.
V5: How does Miller-Rabin improve on Fermat? โ It detects Carmichael numbers using strong pseudoprime tests.
Lab 3: Sieve of Eratosthenes
Objective:
Generate all primes up to N using the Sieve of Eratosthenes.
C++ #include <iostream> #include <vector> using namespace std; int main() { int n = 50; vector<bool> sieve(n+1, true); sieve[0] = sieve[1] = false; for (int p=2; p*p<=n; p++) if (sieve[p]) for (int j=p*p; j<=n; j+=p) sieve[j] = false; cout << "Primes up to " << n << ": "; for (int i=2; i<=n; i++) if (sieve[i]) cout << i << " "; return 0; }
Viva Voce:
V1: Time complexity? โ O(n log log n).
V2: Space complexity? โ O(n) for the boolean array.
V3: Why start marking from pยฒ? โ Smaller multiples of p were already marked by smaller primes.
V4: Can we optimize memory? โ Yes, bitwise sieve uses bits instead of bytes (8ร savings).
V5: What is the prime counting function ฯ(n)? โ Number of primes โค n. ฯ(10โถ) = 78498.
Lab 4: Segmented Sieve
Objective:
Find all primes in a given range [L, R] using the segmented sieve approach.
Python import math def segmented_sieve(L, R): limit = int(math.sqrt(R)) + 1 mark = [True] * (limit + 1) primes = [] for p in range(2, limit + 1): if mark[p]: primes.append(p) for j in range(p*p, limit+1, p): mark[j] = False is_prime = [True] * (R - L + 1) for p in primes: start = max(p*p, ((L+p-1)//p)*p) for j in range(start, R+1, p): is_prime[j-L] = False if L <= 1: is_prime[1-L] = False return [L+i for i in range(R-L+1) if is_prime[i]] print(segmented_sieve(100, 150))
Viva Voce:
V1: Why not use a regular sieve for large ranges? โ Memory constraint: sieve of 10โน needs ~1 GB.
V2: Memory advantage? โ O(โR) vs O(R).
V3: How to choose segment size? โ Typically โR or cache size for optimal performance.
V4: Time complexity? โ O((RโL+1) log log R + โR).
V5: Applications? โ SPOJ PRIME1, Project Euler problems, counting primes in ranges.
Lab 5: Sieve of Atkins
Objective:
Implement the Sieve of Atkins using quadratic forms.
Python import math def sieve_of_atkins(limit): sieve = [False] * (limit + 1) for x in range(1, int(math.sqrt(limit)) + 1): for y in range(1, int(math.sqrt(limit)) + 1): n = 4*x*x + y*y if n <= limit and (n%12 == 1 or n%12 == 5): sieve[n] = not sieve[n] n = 3*x*x + y*y if n <= limit and n%12 == 7: sieve[n] = not sieve[n] n = 3*x*x - y*y if x > y and n <= limit and n%12 == 11: sieve[n] = not sieve[n] for r in range(5, int(math.sqrt(limit)) + 1): if sieve[r]: for i in range(r*r, limit+1, r*r): sieve[i] = False return [2,3] + [i for i in range(5, limit+1) if sieve[i]] print(sieve_of_atkins(100))
Viva Voce:
V1: How does Atkins differ from Eratosthenes? โ Uses quadratic forms instead of marking multiples.
V2: What are the three quadratic forms? โ 4xยฒ+yยฒ, 3xยฒ+yยฒ, 3xยฒ-yยฒ with specific modular conditions.
V3: Time complexity? โ O(n / log log n), slightly better than Eratosthenes asymptotically.
V4: When is Atkins faster? โ Theoretically for very large n, but optimized Eratosthenes often wins in practice.
V5: Who invented it? โ A.O.L. Atkin and Daniel J. Bernstein, published in 2004.
Industry Spotlight โ A Day in the Life
๐ฉโ๐ป Priya Nair, 26 โ Cryptography Engineer at Razorpay, Bangalore
Background: B.Tech in Computer Science from NIT Calicut. Competitive programmer โ Codeforces rating 1800+ (Expert), CodeChef 5-star. Interned at Razorpay in 3rd year working on payment gateway security. Converted to full-time offer. Now works on cryptographic modules for payment processing.
A Typical Day:
9:00 AM โ Morning standup with the security engineering team. Review overnight security alerts and vulnerability reports.
10:00 AM โ Code review of TLS implementation updates. Check certificate validation logic and cipher suite configurations.
11:30 AM โ Implement and test prime generation module for the internal key management system. Benchmark with various key sizes (1024, 2048, 4096 bits).
1:00 PM โ Lunch at Razorpay's Bangalore office. Participate in a Codeforces virtual contest during break.
2:00 PM โ Research post-quantum cryptography algorithms. Write internal documentation on lattice-based alternatives to RSA.
4:00 PM โ Pair programming with a junior developer on implementing RSA-OAEP padding scheme. Review their understanding of prime generation.
5:30 PM โ Security audit of a new payment API endpoint. Run automated vulnerability scans using OpenSSL toolkit.
| Detail | Info |
|---|---|
| Tools Used Daily | OpenSSL, C++, Python, Go, HSMs (Hardware Security Modules), Wireshark |
| Entry Salary (2024) | โน8โ12 LPA + ESOPs |
| Mid-Level (3โ5 yrs) | โน15โ25 LPA |
| Senior (7+ yrs) | โน30โ50 LPA |
| Companies Hiring | Razorpay, PhonePe, Visa, Mastercard, NPCI, Juspay, Pine Labs, BharatPe, PayU, Cashfree |
Earn With It โ Freelance & Income Roadmap
๐ฐ Your Earning Path After This Chapter
Portfolio Pieces: Implement and showcase primality testing library on GitHub. Solve 50+ competitive programming problems involving primes.
Earning Avenues:
โข Competitive programming prizes (Codeforces, CodeChef, Google Code Jam) โ โน5,000โโน50,000 per contest
โข Bug bounty programs (HackerOne India: Razorpay, Paytm, CRED) โ โน5,000โโน5,00,000 per bug
โข Freelance security auditing and crypto implementation โ โน10,000โโน50,000/project
โข Technical writing about algorithms and cryptography โ โน2,000โโน8,000/article
โข Open-source contributions to crypto libraries โ builds reputation for high-paying jobs
| Platform | Best For | Typical Rate |
|---|---|---|
| Codeforces/CodeChef | Contest prizes, building competitive programming profile | โน5,000โโน1,00,000/contest |
| HackerOne India | Bug bounty programs (Razorpay, Paytm, etc.) | โน5,000โโน5,00,000/vulnerability |
| Toptal/Upwork | Freelance security consulting, crypto implementations | $30โ$100/hour |
| GitHub Sponsors | Open-source crypto library contributions | $50โ$500/month (sponsorship) |
| Medium/Dev.to | Technical articles on algorithms and cryptography | โน2,000โโน8,000/article |
Chapter Summary
๐ Key Takeaways โ Primality Testing
- A prime number has exactly two distinct factors: 1 and itself. 2 is the only even prime.
- Naive O(n) test: check all divisors from 2 to nโ1. Too slow for n > 10โถ.
- O(โn) optimization: if n is composite, it has a factor โค โn. Check only up to โn.
- 6kยฑ1 trick: all primes > 3 are of the form 6kยฑ1, letting us skip 2/3 of candidates.
- Trial division factorization finds all prime factors in O(โn) by dividing by smallest factors repeatedly.
- Fermat's Little Theorem: a^(pโ1) โก 1 (mod p) for prime p. Basis for probabilistic testing.
- Carmichael numbers (561, 1105, 1729) fool the Fermat test โ they're composite but pass all coprime bases.
- Sieve of Eratosthenes โญ: generates ALL primes up to n in O(n log log n). The most important algorithm in this unit.
- Sieve optimization: start marking from pยฒ, not 2p, since smaller multiples were already marked.
- Segmented Sieve: handles ranges where regular sieve exceeds memory. Uses O(โR) memory.
- Sieve of Atkins: uses quadratic forms. O(n/log log n) time. Mainly theoretical interest.
- Prime factorization enables counting divisors: if N = pโ^aโ ร pโ^aโ ร ..., divisors = ฮ (aแตข+1).
- RSA encryption relies on the difficulty of factoring the product of two large primes.
- India's UPI/NPCI system uses RSA-2048 to secure 10+ billion monthly transactions.
- For single queries: use O(โn). For bulk generation: use Sieve. For very large n: use Miller-Rabin.
- Every competitive programmer must know Sieve of Eratosthenes โ it appears in 20%+ of number theory problems.
- Next prime palindrome: combine palindrome check with primality test. Prime gaps near n โ ln(n).
- Primes are infinite (Euclid's proof, ~300 BC) and their distribution follows the Prime Number Theorem: ฯ(n) โ n/ln(n).
Earning Checkpoint
| Skill | Tool / Method | Portfolio Deliverable | Ready to Earn? |
|---|---|---|---|
| O(โn) Primality Test | C++ / Python | Competitive programming solutions on Codeforces | โ Yes โ foundation for contest problems |
| Prime Factorization | Trial Division | Number theory problem solutions | โ Yes โ common in interviews |
| Fermat Primality Test | Modular Exponentiation | Crypto-related implementations | โ Yes โ useful in security projects |
| Sieve of Eratosthenes | Boolean Array + Iteration | Efficient prime generator library | โ Yes โ essential for competitive coding |
| Segmented Sieve | Range-based Sieving | Advanced contest solutions (SPOJ PRIME1) | โ Yes โ demonstrates advanced skills |
| Cryptography Concepts | RSA, Modular Arithmetic | Security audit reports, crypto implementations | โฌ Partially โ need more depth for professional work |
โ Unit 2 complete. Ready for Unit 3!
[QR: Link to EduArtha video tutorial โ Primality Testing Deep Dive]