Python: Reduce runtime? - python

I recently started to learn python and i'm using CodeWars to train. The task is to return a list [p, p + 4, p + 6, p + 10, p + 12, p + 16] where all of them are primes. The sum of them should be higher than sum_limit. For low values it is working, but at high values (about 2 million) the runtime is high. How can I reduce the runtime?
from math import sqrt; from itertools import count, islice
def find_primes_sextuplet(sum_limit):
for x in range(sum_limit):
if isPrime(x) and isPrime(x+4) and isPrime(x+6) and isPrime(x+10) and isPrime(x+12) and isPrime(x+16):
possible = [x, x+4, x+6, x+10, x+12, x+16]
if sum(possible) > sum_limit:
return possible
def isPrime(n):
return n > 1 and all(n%i for i in islice(count(2), int(sqrt(n)-1)))
print(find_primes_sextuplet(2000000))

For non-negative integer values of n, you can use this:
def isPrime(n):
if n == 1 or n % 2 == 0 or n % 3 == 0:
return False
end = int(sqrt(n)+1)
for start in [5, 7]:
for k in range(start, end, 6):
if n % k == 0:
return False
return True
It won't change the theoretical complexity, but it will reduce the practical running-time.
And if you change the outer loop to for x in range(5, sum_limit), then you can also get rid of the initial check if n == 1 or n % 2 == 0 or n % 3 == 0.

Here's my thinking about reducing complexity and run time.
You can write a sieve in O(n log log n). Here's a reasonable implementation:
def sieve(n):
grid = [None for _ in range(n+1)]
i = 2
while i < n+1:
if grid[i] is None:
grid[i] = True
for p in range(2*i, n+1, i):
grid[p] = False
else:
i += 1
return (index for index, b in enumerate(grid) if b)
There are 6 numbers, and the total amount added to the first number is 48. So the minimum possible value for the first number is (n - 48) / 6. In my sieve we can iterate the generator until number is greater than that.
def get_remaining_sieve(n):
g = sieve(n)
current = next(g)
min_value = (n - 48) / 6
while current < min_value:
current = next(g)
return [current] + list(g)
Now just iterate through every slice of length 6, and check if the separation matches the desired separation (4, 2, 4, 2, 4).
remaining = get_remaining_sieve(n)
for start in range(len(remaining) - 5):
slice = remaining[start:start+6]
differences = [slice[j] - slice[j-1] for j in range(1, 6)]
if differences == [4, 2, 4, 2, 4]:
print(slice)
Summary
Based on those principles, I've come up with this solution:
from itertools import dropwhile, islice
def get_solutions(n):
grid = [None for _ in range(n+1)]
i = 2
while i < n+1:
if grid[i] is None:
grid[i] = True
for p in range(2*i, n+1, i):
grid[p] = False
else:
i += 1
sieve = (index for index, b in enumerate(grid) if b)
min_value = (n - 48) / 6
reduced_sieve = dropwhile(lambda v: v < min_value, sieve)
reference_slice = list(islice(reduced_sieve, 6))
while True:
try:
ref = reference_slice[0]
differences = [v - ref for v in reference_slice[1:]]
if differences == [4, 6, 10, 12, 16]:
yield reference_slice
reference_slice = reference_slice[1:] + [next(reduced_sieve)]
except StopIteration:
break
n = 2000000
print(next(get_solutions(n))) # 695ms
# or for all solutions
for solution in get_solutions(n): # 755ms
print(solution)
This runs in less than a second on my computer.

There are various ways to improve the runtime of your code. For example a lot of numbers are checked for being prime numbers even though their sum is not eligible as a result. Calculating the sum of 6 numbers is faster than checking if they are prime. You could move the sum check above the prime check and only check the numbers for primes if their sum would be eligible.
To improve this further you could skip numbers which will not result in an eligible sum by starting the range at the floor of possible numbers.
x + x + 4 + x + 6 + x + 10 + x + 12 + x + 16 = 6x + 48
which is supposed to be above your sum_limit
6x + 48 >= sum_limit
x >=(sum_limit - 48) / 6
So if your range starts at x you will skip all numbers which would not result in an eligible sum anyway.
You would also be able to improve runtime by skipping even numbers in your loop(via range(y,x,2)).
Further improving the runtime would require you to adjust the isPrime function.

Related

Trouble Finding Least Common Multiple of Numbers 1-20

"""5. 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?"""
list=[]
possibility_list=[]
base=1
numberlist=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for number in numberlist:
for iteration in range(1000):
list.append(iteration*number)
for possibility in list:
if list.count(possibility)==20:
print("Found LCM of [1:21] -->", str(possibility))
possibility_list.append(possibility)
else: continue
print(min(possibility_list))
I am currently trying to solve Euler Problem #5, which wants to find the LCM of numbers 1-20. The code above is brute force, but for some reason it doesn't work. Can someone point me in the right direction?
As of python 3.9 you can compute the least common multiple directly:
from math import lcm
print(lcm(*range(1, 11)))
If that's "cheating", start with a loop like this:
from math import lcm
result = 1
for i in range (1, 11):
result = lcm(result, i)
Then replace lcm with gcd. The two-arg version of gcd (greatest common divisor) has been around since python 3.5:
from math import gcd
result = 1
for i in range (1, 11):
result *= i // gcd(result, i)
Now gcd is something that's relatively easy to implement using Euclid's algorithm. The idea is that if the GCD of two numbers x and y is g, then x = a * g and y = b * g, with a, b relatively prime. If a and b weren't relatively prime, you could divide them by their common multiple and multiply g by that amount. Let's say a >= b. If x is a multiple of y, b must be 1 (again, a and b are relatively prime) and therefore y = g. Otherwise, c = a - b must be relatively prime to both a and b (else they all have a common factor). We can therefore repeat the same reasoning for y and z = x - y until the two numbers become multiples of each other. The sequence must converge because the numbers decrease with every subtraction:
def gcd(x, y):
if x < y:
x, y = y, x
if x % y == 0:
return y
return gcd(x - y, y)
result = 1
for i in range (1, 11):
result *= i // gcd(result, i)
You can probably make this more efficient, but this should be sufficient to form an understanding of how to solve the problem.
A non-recursive GCD might be advisable in the general case, since python supports arbitrary sized integers. You could implemented it as
def gcd(x, y):
while True:
if x < y:
x, y = y, x
if x % y == 0:
return y
x -= y
Even if you're going to use brute force, I suggest that you do it with a little more intelligence. For example, you know that 10 < lcm <= 1 * 2 * ... * 9 * 10 you can therefore write your check like this:
numbers = range(1, 11)
product = 1
for i in numbers:
product *= i
for n in range(max(numbers) + 1, product + 1):
for i in numbers:
if n % i != 0:
break
else:
break
print(n)
The inner loop checks the current possibility against all the numbers. If the loop terminates without breaking, n is a multiple of all the numbers. This triggers the else clause, which breaks out of the outer loop. The result is guaranteed to be correct because if nothing breaks the loop, n will be the multiple of all the numbers.
In all the above cases, it's trivial to include the range [1, 20] in place of [1, 10].
numberlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
def is_prime(num: int) -> bool:
for factor in range(2, num):
if num % factor == 0:
return False
return True
prime_list = list(filter(is_prime, numberlist))
additional_factor_prime = []
for number in numberlist:
temp_factor_list = [*prime_list] + additional_factor_prime
temp_number = number
for index in range(len(temp_factor_list) - 1, -1, -1):
if temp_number in prime_list:
break
cur_factor = temp_factor_list[index]
if temp_number % cur_factor == 0:
temp_factor_list.pop(index)
temp_number //= cur_factor
if temp_number not in temp_factor_list and temp_number != 0 and temp_number != 1:
additional_factor_prime.append(temp_number)
factor_list = [*prime_list] + additional_factor_prime
LCM = 1
for number in factor_list:
LCM *= number
print(LCM)

How can i make my code run faster for large values(upto 100 million)?

Okay so background: I'm solving a question which requires me to find a number 'n' such that n-9, n-3, n+3, n+9 are consecutive prime numbers and n-8, n-4, n+4, n+8 are practical numbers and then I have to add the first four n that satisfy this condition.
The problem: Whether the logic of the code is correct or incorrect is irrelevant here because my code crashes before it reaches 100 million. I can't even check the output of the code, it works fine for 1million but doesn't scale to well for larger numbers.
What i did:
I used the sieve of erath... to get the prime numbers up to 100 million which we will call M. And since practical numbers are divisible by 6 or by 4, I created another set to store those numbers and from that list i then created a set that contained the numbers that satisfy this condition: 'n-8, n-4, n+4, n+8 are practical numbers' which we will call N. Finally I iterate through each element, a, in N and check whether a - 9, a - 3, a + 3, a + 9 are part of the prime number set.
If anyone has any tips on how i can speed this up or any better algorithms it would be greatly appreciated
code
def SieveOfEratosthenes(n):
m = set()
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
prime[0]= False
prime[1]= False
for p in range(n + 1):
if prime[p]:
m.add(p)
return m
#creates set that stores multiples of 4 and 6
def ps1(n):
s = set()
for i in range(1, n+1):
if i%4 == 0 and i%6 == 0:
s.add(i)
return s
#checks whether any number satisfies n -8, n-4, n+4, n+8 must be practical and stores it in a set
def ps2(l):
q = set()
for i in l:
if ((i-8) in l) and ((i-4) in l) and ((i+4) in l) and ((i+8) in l):
q.add(i)
return q
#using the numbers stored in the prev set, i check the last condition n-9, n-3, n+3, n+9 must be in the
prime list
def TotalSieve(k, l):
q = set()
inc = 0
for i in k:
if inc != 4:
if ((i-9) in l) and ((i-3) in l) and ((i+3) in l) and ((i+9) in l):
inc = inc + 1
q.add(i)
else:
print("Found 4")
return q
# driver program
if __name__=='__main__':
n = 1000000000
m = SieveOfEratosthenes(n)
p = ps1(n)
p = ps2(p)
f = TotalSieve(p, m)
elem1 = f.pop()
elem2 = f.pop()
elem3 = f.pop()
elem4 = f.pop()
#add the first four numbers that satisfy the conditions
tot = elem1 + elem2 + elem3 + elem4
print(tot)
First, ps1 is wrong. The test should say or, not and.
Next, if n is divisible by 4, all n-8, n-4, n+4, n+8 are also divisible by 4. If n is not divisible by 4, none of them are divisible by 4, and some of them are also not divisible by 4. Which means you are only interested in n being a multiple of 4.
Finally, I know that this problem implies some serious number-theoretical homework. Brute force wouldn't do it.

How to use recursion to deal with variable numbers of nested for loop?

I am dealing with the following question:
Create a function that accepts two arguments, the number of dice rolled, and the outcome of the roll. The function returns the number of possible combinations that could produce that outcome. The number of dice can vary from 1 to 6.
And below is my code for 4 dice (x=4). But I am not able to extend this to any number of dices (x).
def dice_roll(x, y):
all_comb = []
for i in range(1, 7):
for j in range(1, 7):
for q in range(1, 7):
for r in range(1, 7):
total = i+j+q+r
all_comb.append(total)
return all_comb.count(y)
Is there a way to use recursion to deal with variable numbers of nested loops? And are there other more elegant ways apart from recursion for this question?
As mentioned in the comments you should use itertools.product like this:
import itertools
def dice_roll(dices: int, result: int) -> int:
combos = [x for x in itertools.product(range(1, 7), repeat=dices) if sum(x) == result]
return len(combos)
# combos = [(1, 3), (2, 2), (3, 1)]
if __name__ == '__main__':
print(dice_roll(2, 4))
# returns 3
With itertools.product you get all possible combinations of the given amount of dices. with the list comprehension we filter the values by the correct sum.
Here's a version that calculates the number of rolls for each total in O(n*s) time where n is the number of dice, and s the number of sides. It uses O(n) storage space.
If R[k, t] is the number of rolls of k dice that total t (keeping the number of sides fixed), then the recurrence relations are:
R[0, t] = 1 if t=0, 0 otherwise
R[k, t] = 0 if t < 0
R[k, t] = R[k-1, t-1] + R[k-1, t-2] + ... + R[k-1, t-s]
Then we solving this with dynamic programming.
def dice_roll(n, sides):
A = [1] + [0] * (sides * n)
for k in range(n):
T = sum(A[k] for k in range(max(0, sides*k), sides*(k+1)))
for i in range(sides*(k+1), -1, -1):
A[i] = T
if i > 0:
T -= A[i-1]
if i - sides - 1 >= 0:
T += A[i - sides - 1]
return A
print(dice_roll(9, 4))
The program returns an array A with A[i] storing the number of ways of rolling n dice with s sides that sum to i.
a more mathematical approach using sympy.
for larger numbers of dice this will scale way better than iterating over all possibilities; for small numbers of dice the start-up time of sympy will probably not be worth the trouble.
from sympy.utilities.iterables import partitions, multiset_permutations
def dice_roll(n_dice, total):
ret = 0
for item in partitions(total, k=6, m=n_dice):
if sum(item.values()) != n_dice:
continue
print(f"{item}")
# this for loop is only needed if you want the combinations explicitly
for comb in multiset_permutations(item):
print(f" {comb}")
ret += sum(1 for _ in multiset_permutations(item))
return ret
i get the number of partitions of total first (limiting the maximum value with k=6 as needed for a dice) and then count the number of possible multiset partitions.
the example:
r = dice_roll(n_dice=3, total=5)
print(r)
outputs:
{3: 1, 1: 2}
[1, 1, 3]
[1, 3, 1]
[3, 1, 1]
{2: 2, 1: 1}
[1, 2, 2]
[2, 1, 2]
[2, 2, 1]
6
meaning there are 6 ways to get to 5 with 3 dice. the combinations are shown.
in order to speed up things you could calculate the number of multiset combinations directly (you loose the explicit representation of the possibilities, though):
from sympy.utilities.iterables import partitions, multiset_permutations
from math import comb
def number_multiset_comb(dct):
ret = 1
n = sum(dct.values()) # number of slots
for v in dct.values():
ret *= comb(n, v)
n -= v
return ret
def dice_roll(n_dice, total):
ret = 0
for item in partitions(total, k=6, m=n_dice):
if sum(item.values()) != n_dice:
continue
ret += number_multiset_comb(dct=item)
return ret
def combin_list(n):
# n is number of dice
if n == 1:
return [1,2,3,4,5,6]
else:
temp = combin_list(n-1)
resualt = []
for i in range(1,7):
for item in temp:
resualt.append(i+item)
return resualt
def dice_roll(x, y):
list = combin_list(x)
return list.count(y)

How to efficiently get all combinations where the sum is 10 or below in Python

Imagine you're trying to allocate some fixed resources (e.g. n=10) over some number of territories (e.g. t=5). I am trying to find out efficiently how to get all the combinations where the sum is n or below.
E.g. 10,0,0,0,0 is good, as well as 0,0,5,5,0 etc., while 3,3,3,3,3,3 is obviously wrong.
I got this far:
import itertools
t = 5
n = 10
r = [range(n+1)] * t
for x in itertools.product(*r):
if sum(x) <= n:
print x
This brute force approach is incredibly slow though; there must be a better way?
Timings (1000 iterations):
Default (itertools.product) --- time: 40.90 s
falsetru recursion --- time: 3.63 s
Aaron Williams Algorithm (impl, Tony) --- time: 0.37 s
Possible approach follows. Definitely would use with caution (hardly tested at all, but the results on n=10 and t=5 look reasonable).
The approach involves no recursion. The algorithm to generate partitions of a number n (10 in your example) having m elements (5 in your example) comes from Knuth's 4th volume. Each partition is then zero-extended if necessary, and all the distinct permutations are generated using an algorithm from Aaron Williams which I have seen referred to elsewhere. Both algorithms had to be translated to Python, and that increases the chance that errors have crept in. The Williams algorithm wanted a linked list, which I had to fake with a 2D array to avoid writing a linked-list class.
There goes an afternoon!
Code (note your n is my maxn and your t is my p):
import itertools
def visit(a, m):
""" Utility function to add partition to the list"""
x.append(a[1:m+1])
def parts(a, n, m):
""" Knuth Algorithm H, Combinatorial Algorithms, Pre-Fascicle 3B
Finds all partitions of n having exactly m elements.
An upper bound on running time is (3 x number of
partitions found) + m. Not recursive!
"""
while (1):
visit(a, m)
while a[2] < a[1]-1:
a[1] -= 1
a[2] += 1
visit(a, m)
j=3
s = a[1]+a[2]-1
while a[j] >= a[1]-1:
s += a[j]
j += 1
if j > m:
break
x = a[j] + 1
a[j] = x
j -= 1
while j>1:
a[j] = x
s -= x
j -= 1
a[1] = s
def distinct_perms(partition):
""" Aaron Williams Algorithm 1, "Loopless Generation of Multiset
Permutations by Prefix Shifts". Finds all distinct permutations
of a list with repeated items. I don't follow the paper all that
well, but it _possibly_ has a running time which is proportional
to the number of permutations (with 3 shift operations for each
permutation on average). Not recursive!
"""
perms = []
val = 0
nxt = 1
l1 = [[partition[i],i+1] for i in range(len(partition))]
l1[-1][nxt] = None
#print(l1)
head = 0
i = len(l1)-2
afteri = i+1
tmp = []
tmp += [l1[head][val]]
c = head
while l1[c][nxt] != None:
tmp += [l1[l1[c][nxt]][val]]
c = l1[c][nxt]
perms.extend([tmp])
while (l1[afteri][nxt] != None) or (l1[afteri][val] < l1[head][val]):
if (l1[afteri][nxt] != None) and (l1[i][val]>=l1[l1[afteri][nxt]][val]):
beforek = afteri
else:
beforek = i
k = l1[beforek][nxt]
l1[beforek][nxt] = l1[k][nxt]
l1[k][nxt] = head
if l1[k][val] < l1[head][val]:
i = k
afteri = l1[i][nxt]
head = k
tmp = []
tmp += [l1[head][val]]
c = head
while l1[c][nxt] != None:
tmp += [l1[l1[c][nxt]][val]]
c = l1[c][nxt]
perms.extend([tmp])
return perms
maxn = 10 # max integer to find partitions of
p = 5 # max number of items in each partition
# Find all partitions of length p or less adding up
# to maxn or less
# Special cases (Knuth's algorithm requires n and m >= 2)
x = [[i] for i in range(maxn+1)]
# Main cases: runs parts fn (maxn^2+maxn)/2 times
for i in range(2, maxn+1):
for j in range(2, min(p+1, i+1)):
m = j
n = i
a = [0, n-m+1] + [1] * (m-1) + [-1] + [0] * (n-m-1)
parts(a, n, m)
y = []
# For each partition, add zeros if necessary and then find
# distinct permutations. Runs distinct_perms function once
# for each partition.
for part in x:
if len(part) < p:
y += distinct_perms(part + [0] * (p - len(part)))
else:
y += distinct_perms(part)
print(y)
print(len(y))
Make your own recursive function which do not recurse with an element unless it's possible to make a sum <= 10.
def f(r, n, t, acc=[]):
if t == 0:
if n >= 0:
yield acc
return
for x in r:
if x > n: # <---- do not recurse if sum is larger than `n`
break
for lst in f(r, n-x, t-1, acc + [x]):
yield lst
t = 5
n = 10
for xs in f(range(n+1), n, 5):
print xs
You can create all the permutations with itertools, and parse the results with numpy.
>>> import numpy as np
>>> from itertools import product
>>> t = 5
>>> n = 10
>>> r = range(n+1)
# Create the product numpy array
>>> prod = np.fromiter(product(r, repeat=t), np.dtype('u1,' * t))
>>> prod = prod.view('u1').reshape(-1, t)
# Extract only permutations that satisfy a condition
>>> prod[prod.sum(axis=1) < n]
Timeit:
>>> %%timeit
prod = np.fromiter(product(r, repeat=t), np.dtype('u1,' * t))
prod = prod.view('u1').reshape(-1, t)
prod[prod.sum(axis=1) < n]
10 loops, best of 3: 41.6 ms per loop
You could even speed up the product computation by populating combinations directly in numpy.
You could optimize the algorithm using Dynamic Programming.
Basically, have an array a, where a[i][j] means "Can I get a sum of j with the elements up to the j-th element (and using the jth element, assuming you have your elements in an array t (not the number you mentioned)).
Then you can fill the array doing
a[0][t[0]] = True
for i in range(1, len(t)):
a[i][t[i]] = True
for j in range(t[i]+1, n+1):
for k in range(0, i):
if a[k][j-t[i]]:
a[i][j] = True
Then, using this info, you could backtrack the solution :)
def backtrack(j = len(t)-1, goal = n):
print j, goal
all_solutions = []
if j == -1:
return []
if goal == t[j]:
all_solutions.append([j])
for i in range(j-1, -1, -1):
if a[i][goal-t[j]]:
r = backtrack(i, goal - t[j])
for l in r:
print l
l.append(j)
all_solutions.append(l)
all_solutions.extend(backtrack(j-1, goal))
return all_solutions
backtrack() # is the answer

Prime factorization - list

I am trying to implement a function primeFac() that takes as input a positive integer n and returns a list containing all the numbers in the prime factorization of n.
I have gotten this far but I think it would be better to use recursion here, not sure how to create a recursive code here, what would be the base case? to start with.
My code:
def primes(n):
primfac = []
d = 2
while (n > 1):
if n%d==0:
primfac.append(d)
# how do I continue from here... ?
A simple trial division:
def primes(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d) # supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
with O(sqrt(n)) complexity (worst case). You can easily improve it by special-casing 2 and looping only over odd d (or special-casing more small primes and looping over fewer possible divisors).
The primefac module does factorizations with all the fancy techniques mathematicians have developed over the centuries:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
This is a comprehension based solution, it might be the closest you can get to a recursive solution in Python while being possible to use for large numbers.
You can get proper divisors with one line:
divisors = [ d for d in xrange(2,int(math.sqrt(n))) if n % d == 0 ]
then we can test for a number in divisors to be prime:
def isprime(d): return all( d % od != 0 for od in divisors if od != d )
which tests that no other divisors divides d.
Then we can filter prime divisors:
prime_divisors = [ d for d in divisors if isprime(d) ]
Of course, it can be combined in a single function:
def primes(n):
divisors = [ d for d in range(2,n//2+1) if n % d == 0 ]
return [ d for d in divisors if \
all( d % od != 0 for od in divisors if od != d ) ]
Here, the \ is there to break the line without messing with Python indentation.
I've tweaked #user448810's answer to use iterators from itertools (and python3.4, but it should be back-portable). The solution is about 15% faster.
import itertools
def factors(n):
f = 2
increments = itertools.chain([1,2,2], itertools.cycle([4,2,4,2,4,6,2,6]))
for incr in increments:
if f*f > n:
break
while n % f == 0:
yield f
n //= f
f += incr
if n > 1:
yield n
Note that this returns an iterable, not a list. Wrap it in list() if that's what you want.
Most of the above solutions appear somewhat incomplete. A prime factorization would repeat each prime factor of the number (e.g. 9 = [3 3]).
Also, the above solutions could be written as lazy functions for implementation convenience.
The use sieve Of Eratosthenes to find primes to test is optimal, but; the above implementation used more memory than necessary.
I'm not certain if/how "wheel factorization" would be superior to applying only prime factors, for division tests of n.
While these solution are indeed helpful, I'd suggest the following two functions -
Function-1 :
def primes(n):
if n < 2: return
yield 2
plist = [2]
for i in range(3,n):
test = True
for j in plist:
if j>n**0.5:
break
if i%j==0:
test = False
break
if test:
plist.append(i)
yield i
Function-2 :
def pfactors(n):
for p in primes(n):
while n%p==0:
yield p
n=n//p
if n==1: return
list(pfactors(99999))
[3, 3, 41, 271]
3*3*41*271
99999
list(pfactors(13290059))
[3119, 4261]
3119*4261
13290059
Here is my version of factorization by trial division, which incorporates the optimization of dividing only by two and the odd integers proposed by Daniel Fischer:
def factors(n):
f, fs = 3, []
while n % 2 == 0:
fs.append(2)
n /= 2
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += 2
if n > 1: fs.append(n)
return fs
An improvement on trial division by two and the odd numbers is wheel factorization, which uses a cyclic set of gaps between potential primes to greatly reduce the number of trial divisions. Here we use a 2,3,5-wheel:
def factors(n):
gaps = [1,2,2,4,2,4,2,4,6,2,6]
length, cycle = 11, 3
f, fs, nxt = 2, [], 0
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += gaps[nxt]
nxt += 1
if nxt == length:
nxt = cycle
if n > 1: fs.append(n)
return fs
Thus, print factors(13290059) will output [3119, 4261]. Factoring wheels have the same O(sqrt(n)) time complexity as normal trial division, but will be two or three times faster in practice.
I've done a lot of work with prime numbers at my blog. Please feel free to visit and study.
def get_prime_factors(number):
"""
Return prime factor list for a given number
number - an integer number
Example: get_prime_factors(8) --> [2, 2, 2].
"""
if number == 1:
return []
# We have to begin with 2 instead of 1 or 0
# to avoid the calls infinite or the division by 0
for i in xrange(2, number):
# Get remainder and quotient
rd, qt = divmod(number, i)
if not qt: # if equal to zero
return [i] + get_prime_factors(rd)
return [number]
Most of the answer are making things too complex. We can do this
def prime_factors(n):
num = []
#add 2 to list or prime factors and remove all even numbers(like sieve of ertosthenes)
while(n%2 == 0):
num.append(2)
n /= 2
#divide by odd numbers and remove all of their multiples increment by 2 if no perfectlly devides add it
for i in xrange(3, int(sqrt(n))+1, 2):
while (n%i == 0):
num.append(i)
n /= i
#if no is > 2 i.e no is a prime number that is only divisible by itself add it
if n>2:
num.append(n)
print (num)
Algorithm from GeeksforGeeks
prime factors of a number:
def primefactors(x):
factorlist=[]
loop=2
while loop<=x:
if x%loop==0:
x//=loop
factorlist.append(loop)
else:
loop+=1
return factorlist
x = int(input())
alist=primefactors(x)
print(alist)
You'll get the list.
If you want to get the pairs of prime factors of a number try this:
http://pythonplanet.blogspot.in/2015/09/list-of-all-unique-pairs-of-prime.html
def factorize(n):
for f in range(2,n//2+1):
while n%f == 0:
n //= f
yield f
It's slow but dead simple. If you want to create a command-line utility, you could do:
import sys
[print(i) for i in factorize(int(sys.argv[1]))]
Here is an efficient way to accomplish what you need:
def prime_factors(n):
l = []
if n < 2: return l
if n&1==0:
l.append(2)
while n&1==0: n>>=1
i = 3
m = int(math.sqrt(n))+1
while i < m:
if n%i==0:
l.append(i)
while n%i==0: n//=i
i+= 2
m = int(math.sqrt(n))+1
if n>2: l.append(n)
return l
prime_factors(198765430488765430290) = [2, 3, 5, 7, 11, 13, 19, 23, 3607, 3803, 52579]
You can use sieve Of Eratosthenes to generate all the primes up to (n/2) + 1 and then use a list comprehension to get all the prime factors:
def rwh_primes2(n):
# http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a list of primes, 2 <= p < n """
correction = (n%6>1)
n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
sieve = [True] * (n/3)
sieve[0] = False
for i in xrange(int(n**0.5)/3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)/3) ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1)
sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1)
return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]
def primeFacs(n):
primes = rwh_primes2((n/2)+1)
return [x for x in primes if n%x == 0]
print primeFacs(99999)
#[3, 41, 271]
from sets import Set
# this function generates all the possible factors of a required number x
def factors_mult(X):
L = []
[L.append(i) for i in range(2,X) if X % i == 0]
return L
# this function generates list containing prime numbers upto the required number x
def prime_range(X):
l = [2]
for i in range(3,X+1):
for j in range(2,i):
if i % j == 0:
break
else:
l.append(i)
return l
# This function computes the intersection of the two lists by invoking Set from the sets module
def prime_factors(X):
y = Set(prime_range(X))
z = Set(factors_mult(X))
k = list(y & z)
k = sorted(k)
print "The prime factors of " + str(X) + " is ", k
# for eg
prime_factors(356)
Simple way to get the desired solution
def Factor(n):
d = 2
factors = []
while n >= d*d:
if n % d == 0:
n//=d
# print(d,end = " ")
factors.append(d)
else:
d = d+1
if n>1:
# print(int(n))
factors.append(n)
return factors
This is the code I made. It works fine for numbers with small primes, but it takes a while for numbers with primes in the millions.
def pfactor(num):
div = 2
pflist = []
while div <= num:
if num % div == 0:
pflist.append(div)
num /= div
else:
div += 1
# The stuff afterwards is just to convert the list of primes into an expression
pfex = ''
for item in list(set(pflist)):
pfex += str(item) + '^' + str(pflist.count(item)) + ' * '
pfex = pfex[0:-3]
return pfex
I would like to share my code for finding the prime factors of number given input by the user:
a = int(input("Enter a number: "))
def prime(a):
b = list()
i = 1
while i<=a:
if a%i ==0 and i!=1 and i!=a:
b.append(i)
i+=1
return b
c = list()
for x in prime(a):
if len(prime(x)) == 0:
c.append(x)
print(c)
def prime_factors(num, dd=2):
while dd <= num and num>1:
if num % dd == 0:
num //= dd
yield dd
dd +=1
Lot of answers above fail on small primes, e.g. 3, 5 and 7. The above is succinct and fast enough for ordinary use.
print list(prime_factors(3))
[3]

Categories

Resources