Prime Factors of a Number
Intro
For an introduction on prime factorization, peruse Prime Factorization article on Math Is Fun.
If we divide a number as many times as possible by 2, it means the resulting quotient won’t be divisible by multiples of 2 (4, 8, 12, etc.).
λ> 24 / 2
12.0
λ> 12 / 2
6.0
λ> 6 / 2
3.0
The quotient 3 cannot be divided by 2, but neither by 4, or 8, or 12, etc.
As another example, if a number is divided by 3 as many times as possible, the resulting quotient can’t be divided by multiples of 3 (6, 9, 12, etc.).
λ> 18 / 2
9.0
λ> 9 / 3
3.0
λ> 3 / 3
1.0
Divide 18 by the smallest prime: 2. The quotient is 9, which we divide by the next smallest prime: 3. The quotient is 3, which can still be divided by 3. The quotient is now 1. It cannot be divided by multiples of three, that is, 6, or 9, or 12, etc.
The above ideas about division helps to understand some of the possible implementations of algorithms to find the prime factors of a number.
C solution with loops
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 8
int factors(int n, int *ps) {
int len = 0,
d;
for (d = 2; n > 1; ++d)
while (n % d == 0) {
*(ps + len++) = d;
n = n / d;
}
return len;
}
Keep dividing n
by d
, so, at some point d
will be 1 or less than 1, which is why we check \(n \gt 1\).
The condition \(n \gt 1\) can be replaced with the condition \(i \le n\) and the resulting primes found should be the same. |
Test the function with a few inputs:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *ps = malloc(sizeof(int) * MAX_LEN);
int len;
len = factors(24, ps);
printf("\nFound %d prime factors for 24:\n", len);
for (int i = 0; i < len; ++i)
printf("• %d\n", *(ps + i));
len = factors(101, ps);
printf("\nFound %d prime factors for 101:\n", len);
for (int i = 0; i < len; ++i)
printf("• %d\n", *(ps + i));
len = factors(315, ps);
printf("\nFound %d prime factors for 315:\n", len);
for (int i = 0; i < len; ++i)
printf("• %d\n", *(ps + i));
free(ps);
return 0;
}
sqrt
People implement solutions with loop testing divisibility only up to the square root of the target number.
while i <= int(sqrt(n))
while (i <= (int)sqrt((double)n)))
We can avoid having to deal with doubles vs ints and the use of sqrt()
by using \(i * i \le n\) instead of \(i \le sqrt(n)\).
More info on this Stack Overflow Answer.
Recursive Solution in C
Here’s one solution from the book Mastering Algorithms with C, with my own modifications to return a pointer to an array of prime factors instead of printing them.
#include <stdio.h>
#include <stdlib.h>
int factor(int x, int n, int j, int *ps, int idx) {
int i;
if (n == 1) {
printf("1 is a unit.\n");
return ++idx;
}
i = j;
while (i * i <= n) {
if (n % i == 0) {
*(ps + idx) = i;
factor(x, (int)(n / i), i, ps, ++idx);
return ++idx;
} else {
++i;
}
}
if (n == x)
printf("%d is prime.\n", x);
else
*(ps + idx) = n;
return ++idx;
}
int main(void) {
int *ps = malloc(sizeof(int) * 4);
int i, len;
len = factor(18, 18, 2, ps, 0);
for (i = 0; i <= len; ++i)
printf("%d\n", *(ps + i));
free(ps);
}
Recursive solution in Python
def factors(x, n, j, ps = []):
if n == 1:
return 1
i = j
while i * i <= n:
if n % i == 0:
ps.append(i)
factors(x, int(n / i), i, ps)
return ps
else:
i = i + 1
if x == n:
return "%d is prime" % x
else:
ps.append(n)
return ps
print(factors(18, 18, 2, []))
#=> [2, 3, 3]
Found 4 prime factors for 24:
• 2
• 2
• 2
• 3
Found 1 prime factors for 101:
• 101
Found 4 prime factors for 315:
• 3
• 3
• 5
• 7