python optimizing prime number generator - python

Here is the code for generating a prime number sequence. This code in particular, takes the users input as an integer (if it can), and prints out that many numbers of the prime number sequence. Is there any way to optimize this particular script so that it runs faster and can process bigger numbers at a greater speed?
P = 2
Count = 1
X = int(raw_input('choose number: '))
def Main(P, X):
while Count <= X:
isprime = True
for x in range(2, P - 1):
if P % x == 0:
isprime = False
if isprime:
print P
Count += 1
P += 1
Main(P, X)

n-th prime is less than N = max(12, n*(log(n) + log(log(n)))). Knowing N, you could use any solution from Fastest way to list all primes below N link provided by #Jonathan Davies.
For example, using a simple Sieve of Eratosthenes implementation, here's live example:
#!/usr/bin/env python2
from itertools import islice
from math import log
def iprimes_upto(limit):
is_prime = [True] * limit
for n in xrange(2, limit):
if is_prime[n]:
yield n
for i in xrange(n*n, limit, n): # start at ``n`` squared
is_prime[i] = False
n = int(raw_input('Choose number of primes to print: '))
N = max(12, int(n*(log(n) + log(log(n))) + .5)) # find limit
for p in islice(iprimes_upto(N), n): # get n primes
print p
As an alternative, you could use an infinite prime generator (you don't need to compute the limit in this case).

Related

finding the smallest prime factors of a number using python [duplicate]

Two part question:
Trying to determine the largest prime factor of 600851475143, I found this program online that seems to work. The problem is, I'm having a hard time figuring out how it works exactly, though I understand the basics of what the program is doing. Also, I'd like if you could shed some light on any method you may know of finding prime factors, perhaps without testing every number, and how your method works.
Here's the code that I found online for prime factorization [NOTE: This code is incorrect. See Stefan's answer below for better code.]:
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print(n)
#takes about ~0.01secs
Why is that code so much faster than this code, which is just to test the speed and has no real purpose other than that?
i = 1
while i < 100:
i += 1
#takes about ~3secs
This question was the first link that popped up when I googled "python prime factorization".
As pointed out by #quangpn88, this algorithm is wrong (!) for perfect squares such as n = 4, 9, 16, ... However, #quangpn88's fix does not work either, since it will yield incorrect results if the largest prime factor occurs 3 or more times, e.g., n = 2*2*2 = 8 or n = 2*3*3*3 = 54.
I believe a correct, brute-force algorithm in Python is:
def largest_prime_factor(n):
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return n
Don't use this in performance code, but it's OK for quick tests with moderately large numbers:
In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop
If the complete prime factorization is sought, this is the brute-force algorithm:
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
Ok. So you said you understand the basics, but you're not sure EXACTLY how it works. First of all, this is a great answer to the Project Euler question it stems from. I've done a lot of research into this problem and this is by far the simplest response.
For the purpose of explanation, I'll let n = 20. To run the real Project Euler problem, let n = 600851475143.
n = 20
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
This explanation uses two while loops. The biggest thing to remember about while loops is that they run until they are no longer true.
The outer loop states that while i * i isn't greater than n (because the largest prime factor will never be larger than the square root of n), add 1 to i after the inner loop runs.
The inner loop states that while i divides evenly into n, replace n with n divided by i. This loop runs continuously until it is no longer true. For n=20 and i=2, n is replaced by 10, then again by 5. Because 2 doesn't evenly divide into 5, the loop stops with n=5 and the outer loop finishes, producing i+1=3.
Finally, because 3 squared is greater than 5, the outer loop is no longer true and prints the result of n.
Thanks for posting this. I looked at the code forever before realizing how exactly it worked. Hopefully, this is what you're looking for in a response. If not, let me know and I can explain further.
It looks like people are doing the Project Euler thing where you code the solution yourself. For everyone else who wants to get work done, there's the primefac module which does very large numbers very quickly:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
For prime number generation I always use the Sieve of Eratosthenes:
def primes(n):
if n<=2:
return []
sieve=[True]*(n+1)
for x in range(3,int(n**0.5)+1,2):
for y in range(3,(n//x)+1,2):
sieve[(x*y)]=False
return [2]+[i for i in range(3,n,2) if sieve[i]]
In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop
In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop
You can use Miller-Rabin primality test to check whether a number is prime or not. You can find its Python implementations here.
Always use timeit module to time your code, the 2nd one takes just 15us:
def func():
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop
def func():
i=1
while i<100:i+=1
....:
In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
If you are looking for pre-written code that is well maintained, use the function sympy.ntheory.primefactors from SymPy.
It returns a sorted list of prime factors of n.
>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]
Pass the list to max() to get the biggest prime factor: max(primefactors(6008))
In case you want the prime factors of n and also the multiplicities of each of them, use sympy.ntheory.factorint.
Given a positive integer n, factorint(n) returns a dict containing the
prime factors of n as keys and their respective multiplicities as
values.
>>> from sympy.ntheory import factorint
>>> factorint(6008) # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}
The code is tested against Python 3.6.9 and SymPy 1.1.1.
"""
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
"""
from sympy import primefactors
print(primefactors(600851475143)[-1])
def find_prime_facs(n):
list_of_factors=[]
i=2
while n>1:
if n%i==0:
list_of_factors.append(i)
n=n/i
i=i-1
i+=1
return list_of_factors
Isn't largest prime factor of 27 is 3 ??
The above code might be fastest,but it fails on 27 right ?
27 = 3*3*3
The above code returns 1
As far as I know.....1 is neither prime nor composite
I think, this is the better code
def prime_factors(n):
factors=[]
d=2
while(d*d<=n):
while(n>1):
while n%d==0:
factors.append(d)
n=n/d
d+=1
return factors[-1]
Another way of doing this:
import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
while n % i == 0:
#print i,"|",n
n = n/i
result.append(i)
if n == 1:
break
if n > 1: result.append(n)
print result
sample output :
python test.py 68
[2, 2, 17]
The code is wrong with 100. It should check case i * i = n:
I think it should be:
while i * i <= n:
if i * i = n:
n = i
break
while n%i == 0:
n = n / i
i = i + 1
print (n)
My code:
# METHOD: PRIME FACTORS
def prime_factors(n):
'''PRIME FACTORS: generates a list of prime factors for the number given
RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
'''
num = n #number at the end
count = 0 #optimization (to count iterations)
index = 0 #index (to test)
t = [2, 3, 5, 7] #list (to test)
f = [] #prime factors list
while t[index] ** 2 <= n:
count += 1 #increment (how many loops to find factors)
if len(t) == (index + 1):
t.append(t[-2] + 6) #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
if n % t[index]: #if 0 does else (otherwise increments, or try next t[index])
index += 1 #increment index
else:
n = n // t[index] #drop max number we are testing... (this should drastically shorten the loops)
f.append(t[index]) #append factor to list
if n > 1:
f.append(n) #add last factor...
return num, f, f'count optimization: {count}'
Which I compared to the code with the most votes, which was very fast
def prime_factors2(n):
i = 2
factors = []
count = 0 #added to test optimization
while i * i <= n:
count += 1 #added to test optimization
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors, f'count: {count}' #print with (count added)
TESTING, (note, I added a COUNT in each loop to test the optimization)
# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')
I figure this code could be modified easily to get the (largest factor) or whatever else is needed. I'm open to any questions, my goal is to improve this much more as well for larger primes and factors.
In case you want to use numpy here's a way to create an array of all primes not greater than n:
[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]
Check this out, it might help you a bit in your understanding.
#program to find the prime factors of a given number
import sympy as smp
try:
number = int(input('Enter a number : '))
except(ValueError) :
print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
prime_factors.append(number)
else :
for i in range(2, int(number/2) + 1) :
"""while figuring out prime factors of a given number, n
keep in mind that a number can itself be prime or if not,
then all its prime factors will be less than or equal to its int(n/2 + 1)"""
if smp.isprime(i) and number % i == 0 :
while(number % i == 0) :
prime_factors.append(i)
number = number / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
print(i, end = ' ')
This is my python code:
it has a fast check for primes and checks from highest to lowest the prime factors.
You have to stop if no new numbers came out. (Any ideas on this?)
import math
def is_prime_v3(n):
""" Return 'true' if n is a prime number, 'False' otherwise """
if n == 1:
return False
if n > 2 and n % 2 == 0:
return False
max_divisor = math.floor(math.sqrt(n))
for d in range(3, 1 + max_divisor, 2):
if n % d == 0:
return False
return True
number = <Number>
for i in range(1,math.floor(number/2)):
if is_prime_v3(i):
if number % i == 0:
print("Found: {} with factor {}".format(number / i, i))
The answer for the initial question arrives in a fraction of a second.
Below are two ways to generate prime factors of given number efficiently:
from math import sqrt
def prime_factors(num):
'''
This function collectes all prime factors of given number and prints them.
'''
prime_factors_list = []
while num % 2 == 0:
prime_factors_list.append(2)
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
prime_factors_list.append(i)
num /= i
if num > 2:
prime_factors_list.append(int(num))
print(sorted(prime_factors_list))
val = int(input('Enter number:'))
prime_factors(val)
def prime_factors_generator(num):
'''
This function creates a generator for prime factors of given number and generates the factors until user asks for them.
It handles StopIteration if generator exhausted.
'''
while num % 2 == 0:
yield 2
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
yield i
num /= i
if num > 2:
yield int(num)
val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
try:
print(next(prime_gen))
except StopIteration:
print('Generator exhausted...')
break
else:
flag = input('Do you want next prime factor ? "y" or "n":')
if flag == 'y':
continue
elif flag == 'n':
break
else:
print('Please try again and enter a correct choice i.e. either y or n')
Since nobody has been trying to hack this with old nice reduce method, I'm going to take this occupation. This method isn't flexible for problems like this because it performs loop of repeated actions over array of arguments and there's no way how to interrupt this loop by default. The door open after we have implemented our own interupted reduce for interrupted loops like this:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
After that we are able to use some func that is the same as an input of standard Python reduce method. Let this func be defined in a following way:
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
Assuming we want to factor a number 600851475143, an expected output of this function after repeated use of this function should be this:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
The first item of tuple is a number that division method takes and tries to divide by the smallest divisor starting from second item and finishing with square root of this number. If no divisor exists, None is returned.
Now we need to start with iterator defined like this:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
Finally, the result of looping is:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
And outputting prime divisors can be captured by:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
Note:
In order to make it more efficient, you might like to use pregenerated primes that lies in specific range instead of all the values of this range.
You shouldn't loop till the square root of the number! It may be right some times, but not always!
Largest prime factor of 10 is 5, which is bigger than the sqrt(10) (3.16, aprox).
Largest prime factor of 33 is 11, which is bigger than the sqrt(33) (5.5,74, aprox).
You're confusing this with the propriety which states that, if a number has a prime factor bigger than its sqrt, it has to have at least another one other prime factor smaller than its sqrt. So, with you want to test if a number is prime, you only need to test till its sqrt.
def prime(n):
for i in range(2,n):
if n%i==0:
return False
return True
def primefactors():
m=int(input('enter the number:'))
for i in range(2,m):
if (prime(i)):
if m%i==0:
print(i)
return print('end of it')
primefactors()
Another way that skips even numbers after 2 is handled:
def prime_factors(n):
factors = []
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors.append(d)
n = n/d
d += step
step = 2
return factors

Why is code for prime numbers not working for the number 10?

I am trying to write a code in python to find all prime numbers of a number. My problem is that with this line of code it does not work to return the prime numbers of 10, the list only returns 2. Now I adapted this code from this page https://www.geeksforgeeks.org/prime-factor/ as I want to make my factors come out as a list.
The code from that website works for the number 10, however I do not understand why it does not work for number 10 when I run my own slightly modified version of it.
I have tried to +10 at the end of my range function, instead of a +1 and this does solve the problem, however I am still unsure as to why I even have a problem in the first place. Secondly, will the +10 work for all numbers with no error? In theory it should as I should only have factors unto square root of n, but I am not sure again. Lastly, if if the +10 does work, won't that make the code run slower as it will iterate through unneeded loops, how can I improve the speed?
This is my code that I used.
import math
def primefact():
n = int(input('What is your number?:'))
prime_factors = []
while n % 2 == 0: # Checks if number is divisible by 2
prime_factors.append(2) #repeats it until n is no longer divisible by 2
n = n / 2
for i in range(3, int(math.sqrt(n)) + 1, 2): # Testing for odd factors
while n % i == 0:
prime_factors.append(i)
n = n / i
print(prime_factors)
return
primefact()
Here's a piece of code that I wrote:
from numpy import mod, int0, sqrt, add, multiply, subtract, greater, equal, less, not_equal, floor_divide
class findFactors:
def __init__(self, n):
self.primeFactorize(n)
def primeFactorize(self, n):
factors = self.findFactors(n)
self.factors = factors
primeFactors = []
xprimeFactors = []
for factor in factors:
if prime(factor).isPrime:
primeFactors.append(factor)
ntf = n
nprime = 0
while not_equal(ntf, 1):
while equal(mod(ntf, primeFactors[nprime]), 0):
ntf = floor_divide(ntf, primeFactors[nprime])
xprimeFactors.append(primeFactors[nprime])
nprime = add(nprime, 1)
self.primeFactors = primeFactors
self.extendedPrimeFactors = xprimeFactors
def findFactors(self, number):
if prime(number).isPrime: return [1, number]
factors = []
s = int0(sqrt(float(number)))
for v in range(1, add(s, 1)):
if equal(mod(number, v), 0):
factors.append(int(v))
factors.append(int(floor_divide(number, v)))
factors.sort()
return factors
class prime:
def __init__(self, n):
self.isPrime = self.verify(n)
def verify(self, n):
if less(n, 2):
return False
if less(n, 4):
return True
if not n & 1 or equal(mod(n, 3), 0):
return False
s = int0(sqrt(float(n)))
for k in range(1, add(s, 1)):
mul = multiply(6, k)
p = add(mul, 1)
m = subtract(mul, 1)
if greater(m, s):
return True
if equal(mod(n, p), 0) or equal(mod(n, m), 0):
return False
Imagine func = findFactors(n)
func.factors will returns a list with all the factors of the number n,
func.extendedPrimeFactors will return a list with the prime factorization of the number,
func.primeFactors will return a list with the primes appearing only once instead of x times
also, there's a really fast prime checker down there.
(Prime checker usage:
prime(n).isPrime
)
Hi you just forgot the last part of the equation
Condition if n is a prime
# number greater than 2
if n > 2:
print n
Here Is the list of all factorial prime numbers, is not the same as prime numbers
https://en.m.wikipedia.org/wiki/Table_of_prime_factors

how can i check if number entered is prime and if not find its prime factors in python? [duplicate]

Two part question:
Trying to determine the largest prime factor of 600851475143, I found this program online that seems to work. The problem is, I'm having a hard time figuring out how it works exactly, though I understand the basics of what the program is doing. Also, I'd like if you could shed some light on any method you may know of finding prime factors, perhaps without testing every number, and how your method works.
Here's the code that I found online for prime factorization [NOTE: This code is incorrect. See Stefan's answer below for better code.]:
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print(n)
#takes about ~0.01secs
Why is that code so much faster than this code, which is just to test the speed and has no real purpose other than that?
i = 1
while i < 100:
i += 1
#takes about ~3secs
This question was the first link that popped up when I googled "python prime factorization".
As pointed out by #quangpn88, this algorithm is wrong (!) for perfect squares such as n = 4, 9, 16, ... However, #quangpn88's fix does not work either, since it will yield incorrect results if the largest prime factor occurs 3 or more times, e.g., n = 2*2*2 = 8 or n = 2*3*3*3 = 54.
I believe a correct, brute-force algorithm in Python is:
def largest_prime_factor(n):
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return n
Don't use this in performance code, but it's OK for quick tests with moderately large numbers:
In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop
If the complete prime factorization is sought, this is the brute-force algorithm:
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
Ok. So you said you understand the basics, but you're not sure EXACTLY how it works. First of all, this is a great answer to the Project Euler question it stems from. I've done a lot of research into this problem and this is by far the simplest response.
For the purpose of explanation, I'll let n = 20. To run the real Project Euler problem, let n = 600851475143.
n = 20
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
This explanation uses two while loops. The biggest thing to remember about while loops is that they run until they are no longer true.
The outer loop states that while i * i isn't greater than n (because the largest prime factor will never be larger than the square root of n), add 1 to i after the inner loop runs.
The inner loop states that while i divides evenly into n, replace n with n divided by i. This loop runs continuously until it is no longer true. For n=20 and i=2, n is replaced by 10, then again by 5. Because 2 doesn't evenly divide into 5, the loop stops with n=5 and the outer loop finishes, producing i+1=3.
Finally, because 3 squared is greater than 5, the outer loop is no longer true and prints the result of n.
Thanks for posting this. I looked at the code forever before realizing how exactly it worked. Hopefully, this is what you're looking for in a response. If not, let me know and I can explain further.
It looks like people are doing the Project Euler thing where you code the solution yourself. For everyone else who wants to get work done, there's the primefac module which does very large numbers very quickly:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
For prime number generation I always use the Sieve of Eratosthenes:
def primes(n):
if n<=2:
return []
sieve=[True]*(n+1)
for x in range(3,int(n**0.5)+1,2):
for y in range(3,(n//x)+1,2):
sieve[(x*y)]=False
return [2]+[i for i in range(3,n,2) if sieve[i]]
In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop
In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop
You can use Miller-Rabin primality test to check whether a number is prime or not. You can find its Python implementations here.
Always use timeit module to time your code, the 2nd one takes just 15us:
def func():
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop
def func():
i=1
while i<100:i+=1
....:
In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
If you are looking for pre-written code that is well maintained, use the function sympy.ntheory.primefactors from SymPy.
It returns a sorted list of prime factors of n.
>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]
Pass the list to max() to get the biggest prime factor: max(primefactors(6008))
In case you want the prime factors of n and also the multiplicities of each of them, use sympy.ntheory.factorint.
Given a positive integer n, factorint(n) returns a dict containing the
prime factors of n as keys and their respective multiplicities as
values.
>>> from sympy.ntheory import factorint
>>> factorint(6008) # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}
The code is tested against Python 3.6.9 and SymPy 1.1.1.
"""
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
"""
from sympy import primefactors
print(primefactors(600851475143)[-1])
def find_prime_facs(n):
list_of_factors=[]
i=2
while n>1:
if n%i==0:
list_of_factors.append(i)
n=n/i
i=i-1
i+=1
return list_of_factors
Isn't largest prime factor of 27 is 3 ??
The above code might be fastest,but it fails on 27 right ?
27 = 3*3*3
The above code returns 1
As far as I know.....1 is neither prime nor composite
I think, this is the better code
def prime_factors(n):
factors=[]
d=2
while(d*d<=n):
while(n>1):
while n%d==0:
factors.append(d)
n=n/d
d+=1
return factors[-1]
Another way of doing this:
import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
while n % i == 0:
#print i,"|",n
n = n/i
result.append(i)
if n == 1:
break
if n > 1: result.append(n)
print result
sample output :
python test.py 68
[2, 2, 17]
The code is wrong with 100. It should check case i * i = n:
I think it should be:
while i * i <= n:
if i * i = n:
n = i
break
while n%i == 0:
n = n / i
i = i + 1
print (n)
My code:
# METHOD: PRIME FACTORS
def prime_factors(n):
'''PRIME FACTORS: generates a list of prime factors for the number given
RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
'''
num = n #number at the end
count = 0 #optimization (to count iterations)
index = 0 #index (to test)
t = [2, 3, 5, 7] #list (to test)
f = [] #prime factors list
while t[index] ** 2 <= n:
count += 1 #increment (how many loops to find factors)
if len(t) == (index + 1):
t.append(t[-2] + 6) #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
if n % t[index]: #if 0 does else (otherwise increments, or try next t[index])
index += 1 #increment index
else:
n = n // t[index] #drop max number we are testing... (this should drastically shorten the loops)
f.append(t[index]) #append factor to list
if n > 1:
f.append(n) #add last factor...
return num, f, f'count optimization: {count}'
Which I compared to the code with the most votes, which was very fast
def prime_factors2(n):
i = 2
factors = []
count = 0 #added to test optimization
while i * i <= n:
count += 1 #added to test optimization
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors, f'count: {count}' #print with (count added)
TESTING, (note, I added a COUNT in each loop to test the optimization)
# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')
I figure this code could be modified easily to get the (largest factor) or whatever else is needed. I'm open to any questions, my goal is to improve this much more as well for larger primes and factors.
In case you want to use numpy here's a way to create an array of all primes not greater than n:
[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]
Check this out, it might help you a bit in your understanding.
#program to find the prime factors of a given number
import sympy as smp
try:
number = int(input('Enter a number : '))
except(ValueError) :
print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
prime_factors.append(number)
else :
for i in range(2, int(number/2) + 1) :
"""while figuring out prime factors of a given number, n
keep in mind that a number can itself be prime or if not,
then all its prime factors will be less than or equal to its int(n/2 + 1)"""
if smp.isprime(i) and number % i == 0 :
while(number % i == 0) :
prime_factors.append(i)
number = number / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
print(i, end = ' ')
This is my python code:
it has a fast check for primes and checks from highest to lowest the prime factors.
You have to stop if no new numbers came out. (Any ideas on this?)
import math
def is_prime_v3(n):
""" Return 'true' if n is a prime number, 'False' otherwise """
if n == 1:
return False
if n > 2 and n % 2 == 0:
return False
max_divisor = math.floor(math.sqrt(n))
for d in range(3, 1 + max_divisor, 2):
if n % d == 0:
return False
return True
number = <Number>
for i in range(1,math.floor(number/2)):
if is_prime_v3(i):
if number % i == 0:
print("Found: {} with factor {}".format(number / i, i))
The answer for the initial question arrives in a fraction of a second.
Below are two ways to generate prime factors of given number efficiently:
from math import sqrt
def prime_factors(num):
'''
This function collectes all prime factors of given number and prints them.
'''
prime_factors_list = []
while num % 2 == 0:
prime_factors_list.append(2)
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
prime_factors_list.append(i)
num /= i
if num > 2:
prime_factors_list.append(int(num))
print(sorted(prime_factors_list))
val = int(input('Enter number:'))
prime_factors(val)
def prime_factors_generator(num):
'''
This function creates a generator for prime factors of given number and generates the factors until user asks for them.
It handles StopIteration if generator exhausted.
'''
while num % 2 == 0:
yield 2
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
yield i
num /= i
if num > 2:
yield int(num)
val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
try:
print(next(prime_gen))
except StopIteration:
print('Generator exhausted...')
break
else:
flag = input('Do you want next prime factor ? "y" or "n":')
if flag == 'y':
continue
elif flag == 'n':
break
else:
print('Please try again and enter a correct choice i.e. either y or n')
Since nobody has been trying to hack this with old nice reduce method, I'm going to take this occupation. This method isn't flexible for problems like this because it performs loop of repeated actions over array of arguments and there's no way how to interrupt this loop by default. The door open after we have implemented our own interupted reduce for interrupted loops like this:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
After that we are able to use some func that is the same as an input of standard Python reduce method. Let this func be defined in a following way:
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
Assuming we want to factor a number 600851475143, an expected output of this function after repeated use of this function should be this:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
The first item of tuple is a number that division method takes and tries to divide by the smallest divisor starting from second item and finishing with square root of this number. If no divisor exists, None is returned.
Now we need to start with iterator defined like this:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
Finally, the result of looping is:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
And outputting prime divisors can be captured by:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
Note:
In order to make it more efficient, you might like to use pregenerated primes that lies in specific range instead of all the values of this range.
You shouldn't loop till the square root of the number! It may be right some times, but not always!
Largest prime factor of 10 is 5, which is bigger than the sqrt(10) (3.16, aprox).
Largest prime factor of 33 is 11, which is bigger than the sqrt(33) (5.5,74, aprox).
You're confusing this with the propriety which states that, if a number has a prime factor bigger than its sqrt, it has to have at least another one other prime factor smaller than its sqrt. So, with you want to test if a number is prime, you only need to test till its sqrt.
def prime(n):
for i in range(2,n):
if n%i==0:
return False
return True
def primefactors():
m=int(input('enter the number:'))
for i in range(2,m):
if (prime(i)):
if m%i==0:
print(i)
return print('end of it')
primefactors()
Another way that skips even numbers after 2 is handled:
def prime_factors(n):
factors = []
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors.append(d)
n = n/d
d += step
step = 2
return factors

How to find factors of a number using the simplest python method

how to find all factors of a number and list the factors in a list.
Input:
>>>factors(72)
Output:
[2, 2, 2, 3, 3]
I have taken some code down because this is getting a lot of views and this is a HW questions so i don't want it copied.
def factors(n):
a = []
x = 2
while x * x <= n :
if n % x == 0:
a.append(x)
n /= x
else: x += 1
if n > 1: a.append(n)
return a
all downvoted as quickly as possible.
With regard to your question 1: factoring is hard. That's why it's at the core of many cryptographic algorithms --- we currently don't know a way to quickly factor a very large number.
For small numbers, your algorithm will do. For slightly larger numbers, I've had the same question --- apparently Pollard's Rho is a good algorithm for this purpose. For large numbers, we don't know.
Now to your question 2:
First of all, in your prime(n) function, you don't need to check if n%i==0 all the way up to n. You only need to check this up to sqrt(n), because if there is any pair of integers (a,b) such that a * b = n, then one of these integers will necessarily be less than or equal to sqrt(n). So you only need to check up to sqrt(n). This saves you a lot of computations.
Here's your factors function:
from math import ceil
def factors(n):
factors = []
while n > 1:
for i in range(2,int((ceil(n/2.0))+1)):
if n%i==0:
factors.append(i)
n = n/i
continue
factors.append(n)
break
return factors
Here is a solution using decomposition by prime numbers. It is much faster.
import bisect
import math
import pathlib
primes = []
last_prime = None
def _get_primes():
"""
Load all the primes in global primes. Set global last_prime to last prime
read.
"""
global primes
global last_prime
path_to_primes = pathlib.Path(__file__).parent \
.joinpath('../resources/primes.txt')
with path_to_primes.open() as file:
for line in file:
for n in line.split():
n = n.strip()
if n:
n = int(n)
primes.append(n)
last_prime = primes[-1]
def gen_primes_before(n):
"""
Generates all the primes before n in reverse order.
"""
assert n <= last_prime, "Maximum value for n is {}".format(last_prime)
pos = bisect.bisect_left(primes, n)
if pos:
yield from primes[:pos]
def gen_factors(n):
"""
Generates all the factors of a number. May return some values multiple
times. Values returned are not ordered.
"""
type_n = type(n)
assert type_n is int or (type_n is float and n.is_integer()), "Wrong type"
n = int(n)
r = int(math.sqrt(n)) + 1
assert r <= last_prime, "n is over limit"
yield 1
yield n
for prime in gen_primes_before(r):
partner = n/prime
if partner.is_integer():
yield from gen_factors(prime)
yield from gen_factors(partner)
def get_factors(n):
"""
Get all the factors of n as a sorted list.
"""
return sorted(set(gen_factors(n)))
_get_primes()
if __name__ == '__main__':
l = (1e9,)
for n in l:
print("The factors of {} are {}".format(n, get_factors(n)))
I made a repository: https://github.com/Pierre-Thibault/Factor

Calculating the first triangle number to have over 500 divisors in python

I'm trying to solve the 12th problem on Project Euler. I can calculate the number that has over 500 divisors in almost 4 minutes. How can i make it faster? Here's the attempt;
import time
def main():
memo={0:0,1:1}
i=2
n=200
while(1):
if len(getD(getT(i)))>n:
break
i+=1
print(getT(i))
#returns the nth triangle number
def getT(n):
if not n in memo:
memo[n]=n+getT(n-1)
return memo[n]
#returns the list of the divisors
def getD(n):
divisors=[n]
for i in xrange(1,int((n/2)+1)):
if (n/float(i))%1==0:
divisors.append(i)
return divisors
startTime=time.time()
main()
print(time.time()-startTime)
You don't need an array to store the triangle numbers. You can use a single int because you are checking only one value. Also, it might help to use the triangle number formula:n*(n+1)/2 where you find the nth triangle number.
getD also only needs to return a single number, as you are just looking for 500 divisors, not the values of the divisors.
However, your real problem lies in the n/2 in the for loop. By checking factor pairs, you can use sqrt(n). So only check values up to sqrt(n). If you check up to n/2, you get a very large number of wasted tests (in the millions).
So you want to do the following (n is the integer to find number of divisors of, d is possible divisor):
make sure n/d has no remainder.
determine whether to add 1 or 2 to your number of divisors.
Using a decorator (courtesy of activestate recipes) to save previously calculated values, and using a list comprehension to generate the devisors:
def memodict(f):
""" Memoization decorator for a function taking a single argument """
class memodict(dict):
def __missing__(self, key):
ret = self[key] = f(key)
return ret
return memodict().__getitem__
#memodict
def trinumdiv(n):
'''Return the number of divisors of the n-th triangle number'''
numbers = range(1,n+1)
total = sum(numbers)
return len([j for j in range(1,total+1) if total % j == 0])
def main():
nums = range(100000)
for n in nums:
if trinumdiv(n) > 200:
print n
break
Results:
In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def main():
: nums = range(10000)
: for n in nums:
: if trinumdiv(n) > 100:
: print 'Found:', n
: break
:
:startTime=time.time()
:main()
:print(time.time()-startTime)
:--
Found: 384
1.34229898453
and
In [2]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def main():
: nums = range(10000)
: for n in nums:
: if trinumdiv(n) > 200:
: print 'Found:', n
: break
:
:startTime=time.time()
:main()
:print(time.time()-startTime)
:--
Found: 2015
220.681169033
A few comments.
As Quincunx writes, you only need to check the integer range from 1..sqrt(n) which would translate into something like this for i in xrange(1, sqrt(n) + 1): .... This optimization alone vastly speeds up things.
You can use the triangle number formula (which I didn't know until just now, thank you Quincunx), or you can use another approach for finding the triangle numbers than recursion and dictionary lookups. You only need the next number in the sequence, so there is no point in saving it. Function calls involves significant overhead in Python, so recursion is usually not recommended for number crunching. Also, why the cast to float, I didn't quite get that ?
I see that you are already using xrange instead of range to build the int stream. I assume you know that xrange is faster because it is implemented as a generator function. You can do that too. This makes things a lot smoother as well.
I've tried to do just that, use generators, and the code below finds the 500th triangle number in ~16sec on my machine (YMMV). But I've also used a neat trick to find the divisors, which is the quadratic sieve.
Here is my code:
def triangle_num_generator():
""" return the next triangle number on each call
Nth triangle number is defined as SUM([1...N]) """
n = 1
s = 0
while 1:
s += n
n += 1
yield s
def triangle_num_naive(n):
""" return the nth triangle number using the triangle generator """
tgen = triangle_num_generator()
ret = 0
for i in range(n):
ret = tgen.next()
return ret
def divisor_gen(n):
""" finds divisors by using a quadrativ sieve """
divisors = []
# search from 1..sqrt(n)
for i in xrange(1, int(n**0.5) + 1):
if n % i is 0:
yield i
if i is not n / i:
divisors.insert(0, n / i)
for div in divisors:
yield div
def divisors(n):
return [d for d in divisor_gen(n)]
num_divs = 0
i = 1
while num_divs < 500:
i += 1
tnum = triangle_num_naive(i)
divs = divisors(tnum)
num_divs = len(divs)
print tnum # 76576500
Running it produces the following output on my humble machine:
morten#laptop:~/documents/project_euler$ time python pr012.py
76576500
real 0m16.584s
user 0m16.521s
sys 0m0.016s
Using the triangle formula instead of the naive approach:
real 0m3.437s
user 0m3.424s
sys 0m0.000s
I made a code for the same task. It is fairly fast. I used a very fast factor-finding algorithm to find the factors of the number. I also used (n^2 + n)/2 to find the triangle numbers. Here is the code:
from functools import reduce
import time
start = time.time()
n = 1
list_divs = []
while len(list_divs) < 500:
tri_n = (n*n+n)/2 # Generates the triangle number T(n)
list_divs = list(set(reduce(list.__add__,([i, int(tri_n//i)] for i in range(1, int(pow(tri_n, 0.5) + 1)) if tri_n % i == 0)))) # this is the factor generator for any number n
n+=1
print(tri_n, time.time() - start)
It completes the job in 15 seconds on an OK computer.
Here is my answer which solves in about 3 seconds. I think it could be made faster by keeping track of the divisors or generating a prime list to use as divisors... but 3 seconds was quick enough for me.
import time
def numdivisors(triangle):
factors = 0
for i in range(1, int((triangle ** 0.5)) + 1):
if triangle % i == 0:
factors += 1
return factors * 2
def maxtriangledivisors(max):
i = 1
triangle = 0
while i > 0:
triangle += i
if numdivisors(triangle) >= max:
print 'it was found number', triangle,'triangle', i, 'with total of ', numdivisors(triangle), 'factors'
return triangle
i += 1
startTime=time.time()
maxtriangledivisors(500)
print(time.time()-startTime)
Here is another solution to the problem.In this i use Sieve of Eratosthenes to find the primes then doing prime factorisation.
Applying the below formula to calculate number of factors of a number:
total number of factors=(n+1)*(m+1).....
where number=2^n*3^n.......
My best time is 1.9 seconds.
from time import time
t=time()
a=[0]*100
c=0
for i in range(2,100):
if a[i]==0:
for j in range(i*i,100,i):
continue
a[c]=i
c=c+1
print(a)
n=1
ctr=0
while(ctr<=1000):
ctr=1
triang=n*(n+1)/2
x=triang
i=0
n=n+1
while(a[i]<=x):
b=1
while(x%a[i]==0):
b=b+1
x=x//a[i];
i=i+1
ctr=ctr*b
print(triang)
print("took time",time()-t)

Categories