I have a function in python to calculate the prime factors of a number:
def prime_factors(n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
My question is, how many times will the program run to stop on input n?
I can figure it out fairly easy if you take an example such as 56, but abstractly, I cannot seem to write a "formula" for how many times the program will run before having calculated all prime factors.
More of a mathematics question than a programming question, but kinda interesting...
Let the prime factorization of n be of the form:
Where P1 is the smallest prime factor, P2 is the 2nd smallest etc, and Pk is the largest prime factor.
There are two groups of loop iterations to think about:
number of loops that occur because i is a prime factor of n
number of loops that occur because i is not a prime factor of n
Group 1
This number is easier, because it's always the same formula. It's the sum of each of the exponents of the prime factors minus 1, i.e.:
If you think about how the code acts when i is a prime factor (i.e. keeps looping while dividing n by i), the sum of the exponents should be fairly intuitive. You subtract 1 because the last append occurs outside the loop.
Group 2
The second group of loops is slightly more tricky, because the formula itself is actually dependent on whether az > 1, and also on the relative size of Pk and P(k-1) (the second smallest prime factor of n).
If ak > 1, then the last i that went through the loop had the value Pk. So the non-prime factor values of i that were evaluated are all the numbers between 2 and Pk that are not in the set P1 through to Pk. The formula for this turns out to be:
Remember k is the number of distinct prime factors of n. You subtract 1 at the end because it's between 2 and Pk, not 1 and Pk.
On the other hand, let's think about the case where ak = 1 (and ak < 1 is impossible, because ak is the exponent on the largest prime factor - it's got to be 1 or bigger). Then i never took the value of Pk, as the loop ends before that point because of the while i * i <= n: condition.
So in that case, what's the maximum value that i will take? Well it depends.
Remember that if ak = 1, then the last value that n took was Pk. If the second largest prime factor P(k-1) is bigger than the square root of Pk, then once the loop finishes with i = P(k-1), it will immediately exit the loop - so the largest i is P(k-1). On the other hand, if the square root of Pk is bigger, then the loop will continue up to that level before exiting. So the biggest i when ak = 1 is equal to max(P(k-1), Pk**0.5). The formula for the number of loops here would look like:
which simplifies to:
Notice that we take the floor of the square root of Pk, because i will only take integer values.
One formula to...
You put it all together, and it yields:
The loop executes about max(prime_factors(n)) times?
If n is prime, then the worst case is n times.
If I understand your question and since you are not using recursive calls; you are asking "how many times the while loop will execute in order to generate all prime numbers given integer n".
In your code; you are running a while loop with the condition i * i <= n. But since you are manipulating the variable i inside your method the answer is complex(refer #dnozay's answer).
If you are interested read this link which tells how complex it is. Keep read on this link to get insight on prime-counting function.
Related
So i have a mathematical problem about prime power. A number x can be considered a prime power if x = p^k where p is a prime and k is a non-negative integer. For example, 81 is a prime power because 81 = 3^4. Now, form a sequence of numbers in the following way. Start by taking a random number.
If the number is a prime power, end the sequence.
If the number is not a prime power, minus that number with the biggest prime power that's not more than the number itself. Do it over and over again until a prime power is met, then stop.
For example, 34 is not a prime power. Hence we minus it with the highest prime power that's not more than it which is 32, hence 34-32=2. 2 is a prime power, so we stop. In this case, the length of the operation is 2 (because 34 -> 2).
Another example is 95. 95 isn't a prime power, so 95-89=6. 6 is also not a prime power, so we minus it again with the highest prime power, 6-5=1. 1 is a prime power (because 2^0 = 1), so we stop. In this case, the length of the operation is 3 (because 95 -> 6 -> 1).
Known that:
1 is the smallest initial number that can be formed with a length of
1 operation.
6 is the smallest initial number that can be formed with
a length of 2 operations.
95 is the smallest initial number that can
be formed with a length of 3 operations.
360748 is the smallest
initial number that can be formed with a length of 4 operations.
So i want to make an application using Python to find the smallest initial number that can be formed with a length of 5,6 and 7 operations.
Below is the syntax I've came up with. It is using looping to solve the problem. However, to find the smallest initial number that can be formed with a length of 4 or more operations, the program takes a very very long time to run. Is there any way i could improve my code to make the program to run much faster? I just want to focus on getting the number with 5,6 and 7 operations.
from sympy.ntheory import factorint
def pp(q): #to check whether it is a prime power
fact=factorint(q)
p=int(list(fact.keys())[0])
n=int(list(fact.values())[0])
if q!=p**n:
return False
else:
return True
a=[1,6][-1]
b=a*2
d=1
while d!=0:
c=b-a
if pp(b)==False and pp(c)==True:
for i in range(b-1,c-1,-1):
if i==c:
d=0
elif pp(i)==True:
b=i+a
break
elif pp(b)==False:
for i in range(b-1,c-1,-1):
if i==c:
b=b+a+1
elif pp(i)==True:
b=i+a
break
elif pp(b)==True:
b=b+a
b
I know it is a very long process. Thank you so much for your help.
So I was trying to solve a project Euler question that asks we shoud find the largest prime factor of 600851475143.
This is my code:
factors = [i for i in range(1,600851475144) if 600851475143%i is 0]
prime_factors = []
for num in factors:
factors_of_num = [i for i in range(1, num+1) if num%i is 0]
if factors_of_num == [1, num]:
prime_factors.append(num)
print(max(prime_factors))
The issue is that this code won't run for a large number like this. How can \i get this to work?
Your program is executing, but range(1, 600851475144) is just taking a rrrrrrrrrrrrrrrrrrrrrrrreally long time. There are much better ways to get prime factors instead of first checking each number individually whether it is a divisor and then checking which of those are primes.
First, for each pair of divisors p * q = n, either p or q has to be <= sqrt(n), so you'd in fact only have to check the numbers in range(1, 775147) to get one part of those pairs and get the other for free. This alone should be enough to make your program finish in time. But you'd still get all the divisors, and then have to check which of those are prime.
Next, you do not actually have to get all the prime factors of those divisors to determine whether those are prime: You can use any to stop as soon as you find the first non-primitive factor. And here, too, testing up to sqrt(num) is enough. (Also, you could start with the largest divisor, so you can stop the loop as soon as you find the first one that's prime.)
Alternatively, as soon as you find a divisor, divide the target number by that divisor until it can not be divided any more, then continue with the new, smaller target number and the next potential divisor. This way, all your divisors are guaranteed to be prime (otherwise the number would already have been reduced by its prime factors), and you will also need much fewer tests (unless the number itself is prime).
This is the 10th problem in project euler in which we are supposed to find the sum of all the prime numbers below 2 million. I am using Sieve of Eratosthenes algorithm to find the prime numbers. Now I am facing and performance issue with the Sieve of Eratosthenes algorithm.
The performance goes down by a substantial amount if the print(i,"",sum_of_prime) is kept inside the loop. Is there anyway to see it working and keep the performance? If this is done with the conventional method it take some 13 minutes to get the result.
#Euler 10
#Problem:
#The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
#Find the sum of all the primes below two million.
#Author: Kshithij Iyer
#Date of creation: 15/1/2017
import time
#Recording start time of the program
start=time.time()
def sum_of_prime_numbers(limit):
"A function to get the sum prime numbers till the limit"
#Variable to store the sum of prime numbers
sum_of_prime=0
#Sieve of Eratosthenes algorithm
sieve=[True]*limit
for i in range(2,limit):
if sieve[i]:
sum_of_prime=sum_of_prime+i
for j in range(i*i,limit,i):
sieve[j]=False
print(i,"",sum_of_prime)
print("The sum of all the prime numbers below",limit,"is",sum_of_prime)
return
#sum_of_prime_numbers(10)
sum_of_prime_numbers(2000001)
print("Execution time of program is",time.time()-start)
#Note:
#I did give the conventioanl method a try but it didn't work well and was taking
#some 13 minutes to get the results.
#Algorithm for reference
#Input: an integer n > 1
#Let A be an array of Boolean values, indexed by integers 2 to n,
#initially all set to true.
#for i = 2, 3, 4, ..., not exceeding √n:
#if A[i] is true:
#for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n :
#A[j] := false
#Output: all i such that A[i] is true.
So there are various improvements that could be made here:
Firstly, due to the nature of Eratosthenes' sieve, you can replace for i in range(2,limit): with for i in range(2,int(limit**0.5)+1): and the array will be calculated normally, but much faster; however, as a result, you would then have to sum the numbers later.
Also, you are not going to be able to read every individual prime and nor would you want to; instead, you only need the program to tell you milestones, such as every time the program reaches a certain number to check everything against.
Your program does not appear to take into account the fact that arrays start at 0, which should certainly cause some problems; however, this should be fairly fixable.
Finally, it occurs to me that your program appears to count 1 as prime; this should be another easy fix though.
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ? # http://projecteuler.net/problem=3
I have a deal going with myself that if I can't solve a project Euler problem I will understand the best solution I can find. I did write an algorithm which worked for smaller numbers but was too inefficient to work for bigger ones. So I googled Zach Denton's answer and started studying it.
Here is his code:
#!/usr/bin/env python
import math
def factorize(n):
res = []
# iterate over all even numbers first.
while n % 2 == 0:
res.append(2)
n //= 2
# try odd numbers up to sqrt(n)
limit = math.sqrt(n+1)
i = 3
while i <= limit:
if n % i == 0:
res.append(i)
n //= i
limit = math.sqrt(n+i)
else:
i += 2
if n != 1:
res.append(n)
return res
print max(factorize(600851475143))
Here are the bits I can't figure out for myself:
In the second while loop, why does he use a sqrt(n + 1) instead of just sqrt(n)?
Why wouldn't you also use sqrt(n + 1) when iterating over the even numbers in the first while loop?
How does the algorithm manage to find only prime factors? In the algorithm I first wrote I had a separate test for checking whether a factor was prime, but he doesn't bother.
I suspect the +1 has to do with the imprecision of float (I am not sure whether it's actually required, or is simply a defensive move on the author's part).
The first while loop factors all twos out of n. I don't see how sqrt(n + 1) would fit in there.
If you work from small factor to large factors, you automatically eliminate all composite candidates. Think about it: once you've factored out 5, you've automatically factored out 10, 15, 20 etc. No need to check whether they're prime or not: by that point n will not be divisible by them.
I suspect that checking for primality is what's killing your original algorithm's performance.
I am writing a code to find the largest prime factor of a very large number.
Problem 3 of Project Euler :
What is the largest prime factor of the number 600851475143 ?
I coded it in C...but the data type long long int is not sufficient enough to hold the value .
Now, I have rewritten the code in Python. How can I reduce the time taken for execution (as it is taking a considerable amount of time)?
def isprime(b):
x=2
while x<=b/2:
if(b%x)==0:
return 0
x+=1
return 1
def lpf(a):
x=2
i=2
while i<=a/2:
if a%i==0:
if isprime(i)==1:
if i>x:
x=i
print(x)
i+=1
print("final answer"+x)
z=600851475143
lpf(z)
There are many possible algorithmic speed ups. Some basic ones might be:
First, if you are only interested in the largest prime factor, you should check for them from the largest possible ones, not smallest. So instead of looping from 2 to a/2 try to check from a downto 2.
You could load the database of primes instead of using isprime function (there are dozens of such files in the net)
Also, only odd numbers can be primes (except for 2) so you can "jump" 2 values in each iteration
Your isprime checker could also be speededup, you do not have to look for divisiors up to b/2, it is enough to check to sqrt(b), which reduces complexity from O(n) to O(sqrt(n)) (assuming that modulo operation is constant time).
You could use the 128 int provided by GCC: http://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html . This way, you can continue to use C and avoid having to optimize Python's speed. In addition, you can always add your own custom storage type to hold numbers bigger than long long in C.
I think you're checking too many numbers (incrementing by 1 and starting at 2 in each case). If you want to check is_prime by trial division, you need to divide by fewer numbers: only odd numbers to start (better yet, only primes). You can range over odd numbers in python the following way:
for x in range(3, some_limit, 2):
if some_number % x == 0:
etc.
In addition, once you have a list of primes, you should be able to run through that list backwards (because the question asks for highest prime factor) and test if any of those primes evenly divides into the number.
Lastly, people usually go up to the square-root of a number when checking trial division because anything past the square-root is not going to provide new information. Consider 100:
1 x 100
2 x 50
5 x 20
10 x 10
20 x 5
etc.
You can find all the important divisor information by just checking up to the square root of the number. This tip is useful both for testing primes and for testing where to start looking for a potential divisor for that huge number.
First off, your two while loops only need to go up to the sqrt(n) since you will have hit anything past that earlier (you then need to check a/i for primeness as well). In addition, if you find the lowest number that divides it, and the result of the division is prime, then you have found the largest.
First, correct your isprime function:
def isprime(b):
x=2
sqrtb = sqrt(b)
while x<=sqrtb:
if(b%x)==0:
return 0
x+=1
return 1
Then, your lpf:
def lpf(a):
x=2
i=2
sqrta = sqrt(a)
while i<=sqrt(a):
if a%i==0:
b = a//i # integer
if isprime(b):
return b
if isprime(i):
x=i
print(x)
i+=1
return x