Skip to content
Go back

Fast Prime Factorization: Find the Smallest Prime Factor

Published:  at  05:07 PM

Dare to challenge the largest number, the most elusive prime will not resist.

🔮 Problem Statement

We need a function capable of unraveling the structure of any positive integer, revealing its composition in the form of prime factors. But the task does not end there: our ultimate goal is to identify and return the smallest prime factor present in this decomposition.

Here are the specifications:

Parameters:

Returns:

Example:

>>> smallest_prime_factor_master(13195)
5
>>> smallest_prime_factor_master(600851475143)
71

NOTE: Efficiency is paramount. The code must be highly optimized to ensure an execution time of less than 0.1 seconds, even for large numbers.

🧩 Step-by-Step Solution

The strategy is based on the dynamic generation of prime numbers and their successive application in dividing the original number until its complete factorization. The search for the smallest prime divisor is optimized using the property that a non-prime number will always have a factor less than or equal to its square root.

from math import floor, sqrt

We import the floor and sqrt functions from the math module. sqrt is used to calculate the square root of a number, while floor is used to round a number down to the nearest integer. This optimization is crucial to limit the number of iterations needed when checking if a number is prime. 🧠

def is_prime(num):
	if num == 2:
		return True
	if not num % 2 or num == 1:
		return False
	for n in range(3, floor(sqrt(num)) + 1, 2):
		if not num % n:
			return False
	return True

The is_prime(num) function checks if a given number num is prime. First, it handles the special cases of 2 (which is prime) and even numbers (greater than 2) and 1 (which are not prime). Then, it iterates only over odd numbers up to the square root of num. If it finds a divisor, it returns False; otherwise, it returns True.

def generate_prime_numbers():
	n = 2
	while True:
		if is_prime(n):
			yield n
		n += 1

generate_prime_numbers() is a generator that produces prime numbers infinitely. It starts with 2 and increments n in each iteration, using is_prime(n) to determine if n is prime. If it is, yield n returns the value and pauses execution, maintaining state for the next call. It is important to note that the use of yield turns the function into a generator, allowing prime numbers to be generated on demand, avoiding calculating them all in advance and saving memory. 💫

def smallest_prime_factor_master(num):
	"level: master; points: 10; time: 0.1"
	factors = []
	while num != 1:
		for p in generate_prime_numbers():
			if not num % p:
				factors.append(p)
				num //= p
				break
	return min(factors)

Finally, smallest_prime_factor_master(num) implements the main logic. It initializes a list factors. Then, while num is different from 1, it iterates over the primes generated by generate_prime_numbers(). When it finds a prime factor p, it adds it to factors, divides num by p, and breaks the inner loop with break. After the main loop finishes, it returns the minimum value of the factors list.

Complete Solution:

from math import floor, sqrt

def is_prime(num):
	if num == 2:
		return True
	if not num % 2 or num == 1:
		return False
	for n in range(3, floor(sqrt(num)) + 1, 2):
		if not num % n:
			return False
	return True

def generate_prime_numbers():
	n = 2
	while True:
		if is_prime(n):
			yield n
		n += 1

def smallest_prime_factor_master(num):
	"level: master; points: 10; time: 0.1"
	factors = []
	while num != 1:
		for p in generate_prime_numbers():
			if not num % p:
				factors.append(p)
				num //= p
				break
	return min(factors)

🧠 Key Concepts

The key to performance lies in the efficient use of generators. These do not calculate all primes in advance, but produce them on demand, saving memory and computation time. Integer division (//) is crucial to truncate the result to an integer, avoiding floating-point errors that could arise when working with large numbers. Prime factorization is performed iteratively, dividing the original number until it reaches 1. The is_prime function is optimized by taking advantage of the fact that it is only necessary to check divisibility up to the square root of the number. Finally, the algorithmic complexity of the solution is O(sqrt(N)), where N is the input number, due to the optimized primality check and the successive division of the number.

💫 Final Thoughts

A possible improvement would be to implement a cache of already calculated prime numbers, which would avoid recalculating them in subsequent iterations, especially useful if the function is called multiple times with similar numbers. Another optimization could be the use of a more efficient prime number generation algorithm, such as the Sieve of Eratosthenes, although adapted to function as a generator.

Did you know…? The Fundamental Theorem of Arithmetic states that every integer greater than 1 can be expressed as a unique product of prime numbers, regardless of the order of the factors. This theorem is the theoretical basis of prime factorization.

I hope this journey through prime factorization has been as revealing as an expedition to the depths of numbers. Dare to explore more algorithms and optimizations in the fascinating world of programming! If you liked it, leave me a comment and share this article with your colleagues. Keep learning and programming! ✨



Previous Post
Kaprekar Numbers: Discover if a number is magic (Python)
Next Post
Capicúas and Products: Find the Largest with Python