Right algorithm for finding largest prime factor - python

I am trying to find out the largest prime factor of any number. I am doing the program for this problem in python, but there seems to be something wrong with the algorithm that I am following. It seems to fall into an infinite loop. The program goes like this:
def prime(n):
i=0;
while(n!=2):
for i in range(2,n):
if(n%i==0):
prime(n/i);
else:
continue;
print("The highest prime factor is: "),n;
print("Enter a number to find its highest prime factor");
n=input();
prime(n);
Just point out what are the problems here and also mention if there are any other better algorithm than this one for solving this.

EDIT : It feels like I can't manage to be clear without some code, so here it is, with a few modification from yours :
def prime(n):
i=2
while (n%i != 0 and i < n):
i += 1
if (i < n):
return prime (n/i)
else:
print("The highest prime factor is: "),n
print("Enter a number to find its highest prime factor")
n=input()
prime(n)
However, your algorithm is not very efficient. For example, you might consider using Pollard's Rho if you want something better and not long to code.
And even if you want to stick with your idea, you shouldn't do your divisibility tests like this. You may want to run an Erathostene sieve first to only test divisibility by prime factors. Or even only remember the last divisor you found in order to restart the algorithm from there, not from 2.
For example, a little bit better code would be :
def prime(n,a):
i = a
while (n%i != 0 and i*i < n):
i += 1
if (i*i < n):
return prime (n/i, i)
else:
print("The highest prime factor is: "),n
print("Enter a number to find its highest prime factor")
n=input()
prime(n,2)

My solution is rather simple and deals well with huge numbers that would cause memory error in most of the solutions above.
import math
def prime(n):
for x in range(2, int(math.sqrt(n)) + 1):
if n % x == 0:
print n / x
return prime(n / x)
if __name__ == '__main__':
prime(898563214300)
The last printed number is the largest prime factor.

Avoiding recursive calls:
def largest_prime_factor(number):
if number == 1:
return 1
test = 2
while number > 1:
if number % test == 0:
number /= test
else:
test += 1
return test

One simple (but highly inefficient) approach without recursion would be:
(please excuse my python syntax).
Assuming isPrime(k) is a function that returns true if k is prime. It can be implemented using sieve of Erastosenes.
def prime(n):
i=0;
largestPrimeFactor = -1;
for i in range(2,n/2):
if( isPrime(i) && n%i==0 ) :
largestPrimeFactor = i;
print("The highest prime factor is: "),largestPrimeFactor

I can stop your code getting tuck in a loop as follows.
The main problem with the stuck in a loop is the while(n!=2) (or 1 or whatever) is that you don't change n.
Note - it still won't give you prime numbers
def prime(n):
i=0
if(n==2):
print "The highest prime factor is 2"
return
for i in range(2,n):
if(n%i==0):
prime(n/i)
else:
continue
print("The highest prime factor is: "),n
print("Enter a number to find its highest prime factor");
n=input()
prime(n)
Search SO with '[python] primes' for lots of ways to do this properly.

consider this code snippet in C, this is a very efficient algorithm for finding the largest prime factor of a number.
The functions are self-explanatory.
int isPrime(long long int n)
{
long long int i;
for(i=2;i*i<=n;i++)
if(n%i==0)
return 0;
return 1;
}
long long int findLargestPrimeFactor(long long int n)
{
long long int counter=2;
while(n!=1)
{
if(isPrime(n))
return n;
while(n%counter==0)
n/=counter;
counter++;
}
return counter-1;
}

The code can be further optimized as shown below, its written in php but the logic seems fair
for($div=2;$div<=sqrt($n);$div++)
{
if($n%$div==0)
{
$n = $n/$div;
$div--;
}
}
by taking the sq root , you avoid the uncecessary looping.

Related

Calculating the thousandth prime

The problem asks to calculate the 1000th prime number. I am trying to solve this problem but I am stuck.
There are some guidelines on how to solve the problem.
To help you get started, here is a rough outline of the stages you should probably follow in
writing your code:
Initialize some state variables
Generate all (odd) integers > 1 as candidates to be prime
For each candidate integer, test whether it is prime
One easy way to do this is to test whether any other integer > 1 evenly
divides the candidate with 0 remainder. To do this, you can use modular
arithmetic, for example, the expression a%b returns the remainder after
dividing the integer a by the integer b.
You might think about which integers you need to check as divisors –
certainly you don’t need to go beyond the candidate you are checking, buthow much sooner can you stop checking?
If the candidate is prime, print out some information so you know where you are
in the computation, and update the state variables
Stop when you reach some appropriate end condition. In formulating this
condition, don’t forget that your program did not generate the first prime (2).
Use these ideas to guide the creation of your code.
My attempt so far is this
def calculate_thousandth_prime():
j = 0
for i in range(3,int(10e6)):
if i%2 != 0:
counter = 0
for k in range(1, i):
if i%k != 0:
counter += 1
if counter == 0:
print("This candidate is prime")
j += 1
if j == 1001:
print("The number "+str(i)+" is the thousandth prime")
break
return 0
calculate_thousandth_prime()
My code gets stuck on i%k != 0. I must be doing something wrong... any help?
You have two problems:
First, you're searching for k in range(1, i):. Because every number, including primes, is divisible by 1, you won't find any primes. Try searching range(2, i) instead.
Second, you're checking if i%k != 0:. You should be checking that i%k == 0 instead. If i is divisible by any number k, then the number is not prime.
Actually, I found a third issue: You have an off-by-one error. By initializing j=0, your code considers the first prime it finds to be the "zeroth" prime. The code will output the thousand-and-first prime, instead of the thousandth prime.
Changes I made:
Change your range to add a 2 step to skip even numbers more naturally.
Check your inner loop, you need to divide by the values range(2, i//2). Dividing by anything greater than i//2 will be less than 2.
Change your prime check to see if any number in the above range divides. If so, we know the number is false. At that point we can move onto the next number.
We want to return when the prime counter is 1000, you were returning the 1001th prime.
def calculate_thousandth_prime():
prime_counter = 0
for i in range(3,int(10e6),2):
prime = True
for k in range(2, i//2):
if i % k == 0:
prime = False
break
if prime:
print(str(i) + " is prime")
prime_counter += 1
if prime_counter == 1000:
print("The number "+str(i)+" is the thousandth prime")
break
return i
calculate_thousandth_prime()
The sieve of Eratosthenes is generally the fastest way for the early primes. You can adapt it to reach the nth prime.
For example:
def nthPrime(N):
sieve = [1]*(N**2)
p = 2
for _ in range(N):
while not sieve[p]: p += 1
sieve[p::p] = [0]*len(sieve[p::p])
return p
nthPrime(100) # 541
The prime list divisor check method is probably easier to write and understand but it is much slower (although for only 1000 primes, this wouldn't make much of a difference):
def nthPrime(N):
primes = [2]
p = 1
while len(primes)<N:
p += 2
primes += [p]*all(p%d for d in primes)
return p

Why won't my python code display any output for my algorithm?

I am making an algorithm with python to find perfect numbers up to 100000000000000. I have created some code for this that should do it, and it does not throw up any errors, but the code just outputted nothing and is running continuously. I have checked, and the first perfect number is six, so why is my program taking so long to get there?
Here is my code:
number = 1
divisor = 2
factors = 1
if number < 100000000000000:
while True:
number2 = number/divisor
if isinstance(number2, int):
factors = factors + divisor + number2
divisor = divisor + 1
if divisor == number:
if factors == number:
print(number)
number = number + 1
break
In both of these examples, I used the variable "j" for the target number.
This was my first thought, but please do not use it on anything bigger than 10000:
print([i for i in range(1,j+1) if i == sum(k for k in range(1,i//2+1) if i%k == 0)])
Since perfect numbers cannot be prime, I decided to alter a sieve to reduce the amount of numbers to calculate. The sieve can be found here Sieve of Eratosthenes. There is a good explanation there and on the wiki about the sieve.
def SieveOfEratosthenes(n):
prime = [True for i in range(n+1)]
p = 2
while (p * p <= n):
if (prime[p] == True):
for i in range(p * 2, n+1, p):
prime[i] = False
p += 1
for p in range(2, n):
if not prime[p]:
#this is my change
if p == sum(k for k in range(1,p//2+1) if p%k == 0):
yield p
a = SieveOfEratosthenes(j)
b = next(a)
print(b)
try:
while b < j:
b = next(a)
print(b)
except StopIteration:
print("Done")
These work in theory, but I can't get it to work in a "reasonable" amount of time.
Hopefully these will help until someone can post a more efficient solution.
Even if you fix your code, it's the wrong approach for looking for perfect numbers - you're not likely to find more than the first four, and certainly not perfect numbers up to 100,000,000,000,000.
A better approach would be to search for Mersenne primes using a Lucas-Lehmer primality test and when you find one, compute its companion perfect number. This doesn't take much code and will easily eclipse your current approach.

Finding prime numbers < n

I'm working on Project Euler, problem 3.
The problem is:
"The prime factors of 13195 are 5, 7, 13 and 29. What is the largest
prime factor of the number 600851475143?"
In answering this question, I'm breaking down the task to first find all prime numbers < x (in reverse). Why does the following code not seem to work, I'm not sure if it is the logic or incorrect use of operator.
#A function to find prime numbers under n
def find_prime(n):
for i in reversed(xrange(2, n)):
if (n % i) != 0:
print i
find_prime(n)
In testing, I also built a prime number checker for fun, so I have tested somewhat.
def prime_checker(n):
if n > 2:
for i in range (2,n):
if (n % i) == 0:
print "%s is not a prime number" % (n)
break
else:
print "%s is a prime number" % (n)
Can anyone help me understand what I'm doing wrong with the find_prime() function before I move on to the next step that I will use to solve the problem?
Before you start coding, maybe you should read up a bit on what you are dealing with. Primes are well studied. First of all, you do not need all the primes < x. Secondly, every time you find a divisor, you can divide the number by that and have a smaller problem on your hands. In the end, the number that will be left will be what you are looking for. Now, except for 2, no other even numbers are primes, so xrange(3, n, 2). Search some more and you'll find a solution that won't need the time of the universe to finish.
You can't tell whether a number is prime until you make it all the way through the loop without finding any divisors. You're reporting that a number is prime as soon as you find a number that doesn't divide it, but it might still be divisible by some higher number. Your code will say that all odd numbers are prime, because they aren't a multiple of 2.
Also, it's not necessary to go all the way to n in your range. None of the factors of a number can be greater than the square root of the number.
def prime_checker(n):
if n > 2:
for i in range (2, int(n ** .5)+1):
if (n % i) == 0:
print "%s is not a prime number" % (n)
return false
print "%s is a prime number" % (n)
return true

Python several billion iteration loop

I'm new to programming, so please bear with me.
I wrote this code to find the largest prime factor of a number, but when I input a number of a billion or greater it doesn't solve. I've tried xrange, but I'm using Python 3.4. Can anyone point me in the right direction?
done = False
num = int(input("Enter a number: "))
for j in range(num,2,-1):
if (num % j) != 0:
continue
for i in range(2,j):
if (j % i) != 0:
continue
break
else: break
print(j)
It's an O(n^2) algorithm. It doesn't appear to solve because it's just taking a long time. Solution? Use numpy. Or find a non-naive algorithm, or write one yourself. The sieve of Eratosthenes is a good starting point.
Since you are new to programming, here is a simple solution (but know that there are substantially more complex solutions that are more efficient). First note that you only need to check divisors up to the square root of num, since if num = a * b then one is less than the square root and one is larger. Secondly you only need to check for prime divisors.
You can generate a list of primes as follows:
import math
import itertools
def primes_generator():
"""Generator for the infinite list of primes."""
primes = [2, 3]
for prime in primes:
yield prime
for c in itertools.count(5, 2):
bound = math.sqrt(c)
for p in primes:
if not (c % p):
break
if p > bound:
primes.append(c)
yield c
break
Now to find the all the prime divisors:
def prime_factorization(number, primes=None):
if not primes:
primes = primes_generator()
factorization = dict()
for p in primes:
count = 0
while not (number % p):
number = number / p
count = count + 1
if count:
factorization[p] = count
if number == 1:
return factorization
The largest prime divisor is just the largest key in the dictionary. These functions should work fine for fairly large inputs. On my machine the following takes 0.06 seconds.
print(max(prime_factorization(1000000001).keys()))

Prime factorization: doesn't work with large numbers?

I'm trying to find the largest prime factor for a number. The code runs correctly on IDLE when used with smaller numbers, but doesn't seem to print anything to the screen at all when I assign a larger number like 600851475143 to n. Why?
def isPrime(n):
isPrime = True
for i in range(2,n-1):
if n % i == 0:
isPrime = False
return isPrime
largest = 0
n = 600851475143
for i in range(2,n-1):
if isPrime(i) and n % i == 0:
largest = i
n = n / i
continue
print("The largest prime factor is", largest)
I'm running Python 3.3, by the way.
==============================================================================
Thanks everyone!
I fixed my original code as follows:
def isPrime(n):
for i in range(2,n-1):
if n % i == 0:
return False
return True
largest = 0
n = 600851475143
for i in range(2,n-1):
if isPrime(i) and n % i == 0:
largest = i
if i == n:
break
n = n / i
print("The largest prime factor is", largest)
Like nakedfanatic said, their code runs faster, and I edited it slightly:
largest = 0
n = 600851475143
i = 2
while True:
if n % i == 0:
largest = i
if n == i:
# finished
break
n = n / i
else:
i += 1
print("The largest prime factor is", largest)
There are several areas of optimization:
all factorization only needs to got up to sqrt(n) (inclusive)
convert isPrime() to a table lookup
Initialize a lookup table using n, then you compute all primes < sqrt(n) only once and loop through them.
As comments pointed out, this takes up large memory space. We can use bit flag to cut the memory requirement to 1/8, and we can cut it by a further half if we skip all the even numbers (then have to test if n is even separately). But that may still be daunting for LARGE n.
(if using current code) return early in isPrime() (by #justhalf)
loop backwards (from sqrt(n) to 2) when looking up the largest factor
return early if the quotient is 1 after dividing by a factor (by #justhalf)
This post (suggested by #prashant) contains more complicated algorithm (making my suggestion very naive ><):
Fastest way to list all primes below N
... (edits are welcome)
It's because you keep trying even if n is already 1.
This code will help you to see the problem:
def isPrime(n):
for i in xrange(2,n-1):
if n % i == 0:
return False
return True
largest = 0
n = 600851475143
for i in xrange(2,n-1):
print 'Checking whether %d divides %d' % (i,n)
if isPrime(i) and n % i == 0:
largest = i
n = n / i
continue
print("The largest prime factor is", largest)
which will produce:
...
Checking whether 6857 divides 6857
Checking whether 6858 divides 1
Checking whether 6859 divides 1
Checking whether 6860 divides 1
Checking whether 6861 divides 1
Checking whether 6862 divides 1
Checking whether 6863 divides 1
Checking whether 6864 divides 1
Checking whether 6865 divides 1
Checking whether 6866 divides 1
Checking whether 6867 divides 1
Checking whether 6868 divides 1
Checking whether 6869 divides 1
Checking whether 6870 divides 1
Checking whether 6871 divides 1
Checking whether 6872 divides 1
Checking whether 6873 divides 1
...
You should break the loop when n becomes 1, so that it won't do unnecessary checking
n = n / i
if n==1:
break
continue
And anyway, your code might be improved by a lot, haha, see others' suggestions.
Most likely, your code isn't terminating with large n, simply because it takes so long to run through the loop.
Your code is running in O(n²) time, which means it will quickly become unreasonably slow as the size of n increases. That is why your algorithm works for small values, but hangs for large values.
This code does the same thing in O(n) time without doing any prime checking at all, and returns a result instantly:
prime_factors = []
n = 600851475143
i = 2
while True:
if n % i == 0:
prime_factors.append(i)
if n == i:
# finished
break
n = n / i
else:
i += 1
print("The largest prime factor is", prime_factors[-1])
More difficult problems may require a different algorithm.
Check this question out: Fastest way to list all primes below N
Your code looks okay, but could take a long time for a large n. Leveraging math can enable you to do this problem orders of magnitude faster.
On that link, I recommend rwh_primes1 for a pure python solution, and primesfrom3to as one that uses numpy. Both of those implementations are fairly short, relatively clear, and do basically the same thing. Those code snippets are written in Python 2, so a translation might look like this:
def rwh_primes1(n):
sieve = [True] * (n//2)
for i in range(3, int(n**0.5)+1,2):
if sieve[i//2]:
sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
return [2] + [2*i+1 for i in range(1,n//2) if sieve[i]]
isPrime = True
for i in range(2,n-1):
if n % i == 0:
isPrime = False
return isPrime
This loop always exits the first iteration due to the unconditional return. Try:
for i in range(2,n-1):
if n % i == 0:
return False
return True
Also the upper bound n-1 can be reduced to sqrt(n)+1.
Another aspect of your code which may be slowing it down is the second half of your code
largest = 0
n = 600851475143
for i in range(2,n-1):
if isPrime(i) and n % i == 0:
largest = i
n = n / i
continue
Specifically the statement
if isPrime(i) and n % i == 0:
Per the documentation, the second condition is only evaluated if the first one is True. In your case it would make more sense to reverse the conditions so that computationally les expensive division is performed always and the more expensive isPrime() is only called for the actual factors
largest = 0
n = 600851475143
for i in range(2,n-1):
if n % i == 0 and isPrime(i):
largest = i
n = n / i
if n == 1:
break

Categories