Check if a Number is Prime or Not | Maths Playlist
A comprehensive exploration of prime numbers, examining the limitations of naive definitions and algorithms, and developing an optimal solution using square root factor symmetry and time-complexity reduction.
1. Defining a Prime Number: Precision Matters
When asked for the definition of a prime number, people often reply: "A number that is divisible by one and itself."
However, this definition is imprecise and fails edge cases.
The Problem with the Naive Definition
If a prime number is defined only as "divisible by 1 and itself," let's test it against :
- Is divisible by ? Yes.
- Is divisible by "itself" ()? Yes.
- Therefore, under the loose definition, would be classified as a prime number.
- Reality: is not a prime number.
The Correct Mathematical Definition
Note: A prime number is a number strictly greater than that has exactly two distinct positive divisors:
1and the number itself (N).
Let's test numbers against this rigorous standard:
- : Divisors =
{1}(Total = 1 divisor). Not Prime. - : Divisors =
{1, 2}(Total = 2 divisors). Prime. - : Divisors =
{1, 5}(Total = 2 divisors). Prime. - : Divisors =
{1, 2, 5, 10}(Total = 4 divisors). Not Prime. - : Divisors =
{1, 13}(Total = 2 divisors). Prime.
2. The Naive Approach: Linear Scan ()
The most direct way to check if a number is prime is to inspect every integer from up to , counting how many numbers divide evenly.
Naive Algorithm Implementation
bool isPrimeNaive(int n) {
int counter = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
counter++;
}
}
// A prime number must have exactly 2 divisors
if (counter == 2) {
return true;
}
return false;
}
Complexity Analysis
- Time Complexity: because the loop iterates times. If , the algorithm performs one billion operations.
- Space Complexity: because only a primitive counter variable is maintained in memory.
In a technical interview or high-throughput production environment, an solution for large inputs is unacceptable. We need an optimization.
3. Core Mental Model: Factor Symmetry and Square Roots
To optimize our prime-checking algorithm, we can leverage the mathematical property of divisor symmetry explored when finding all divisors of a number.
Real-Life Analogy: Finding Rectangular Plots
Imagine you are asked to find all possible distinct rectangular dimensions (width height) that can form an area of square units.
If you list them out as pairs where :
- (Pairs: 1 and 36)
- (Pairs: 2 and 18)
- (Pairs: 3 and 12)
- (Pairs: 4 and 9)
- (Pairs: 6 and 6) — The turning point
- (Pairs: 9 and 4) — The pairs start repeating in reverse order!
Notice that all factors occur in pairs on either side of . Once you cross , the divisors simply mirror the ones you have already found. Therefore, you never need to search beyond to find all factors.
4. Step-by-Step Evolution: Optimizing Divisor Counting
Let's apply the square root property to our divisor-counting logic. Instead of running our loop up to , we run it up to .
Handling Dual Factors and Perfect Squares
When iterating up to , whenever we find a divisor (such that ), we actually uncover two divisors simultaneously:
in / i(the counterpart divisor)
Crucial Edge Case (Perfect Squares):
If and , then n / i is also . We must ensure we do not count twice!
- If
iis equal ton / i, we increment our counter by1. - If
iis not equal ton / i(e.g., and ), we increment our counter by2.
5. Early Exit Optimization for Primality
Remember: our goal is not to list or count all divisors, but simply to answer: "Is this number prime?"
A prime number has at most two divisors ( and itself). If at any point during our iteration we discover a third divisor, we can immediately declare that the number is not prime and break out of the loop early, saving valuable CPU cycles.
6. Complete Optimized Code Implementation
Here is the clean, optimized C++ implementation incorporating the square root bound, duplicate checks, and early exit strategy:
#include <iostream>
using namespace std;
bool isPrime(int n) {
if (n <= 1) return false; // 1 and negative numbers are not prime
int counter = 0;
// Loop runs up to sqrt(n), expressed as (i * i <= n) to avoid floating-point inaccuracies
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
counter++; // Count 'i'
// Count the counterpart divisor if it's different from 'i'
if ((n / i) != i) {
counter++;
}
}
// Early exit optimization: if divisors exceed 2, it's not prime
if (counter > 2) {
return false;
}
}
// A prime number will have exactly 2 divisors (1 and n)
return (counter == 2);
}
int main() {
int n = 37;
if (isPrime(n)) {
cout << n << " is a Prime Number." << endl;
} else {
cout << n << " is NOT a Prime Number." << endl;
}
return 0;
}
7. Comparative Strategy Analysis
Summary and Key Takeaways
- Redefining Primes: A prime number is strictly greater than and has exactly two divisors: and itself. This correctly excludes from being classified as prime.
- The Naive Flaw: Checking divisibility up to results in an inefficient linear time complexity.
- Divisor Symmetry: Factors always exist in pairs that mirror each other across the square root of the number ().
- Loop Boundary Optimization: By running the loop only while , we reduce the time complexity from to .
- Handling Counterparts: When , account for both and , taking care not to double-count perfect square roots (e.g., ).
- Early Termination: Because primality only requires knowing if divisors exceed two, breaking out of the loop the moment
counter > 2optimizes execution for composite numbers. - Space Efficiency: All algorithms discussed operate in auxiliary space since only scalar tracking variables are used.