Basic prime number generator in Python - python

Just wanted some feedback on my prime number generator. e.g. is it ok, does it use to much resources etc. It uses no libraries, it's fairly simple, and it is a reflection of my current state of programming skills, so don't hold back as I want to learn.
def prime_gen(n):
primes = [2]
a = 2
while a < n:
counter = 0
for i in primes:
if a % i == 0:
counter += 1
if counter == 0:
primes.append(a)
else:
counter = 0
a = a + 1
print primes

There are a few optimizations thar are common:
Example:
def prime(x):
if x in [0, 1]:
return False
if x == 2:
return True
for n in xrange(3, int(x ** 0.5 + 1)):
if x % n == 0:
return False
return True
Cover the base cases
Only iterate up to the square root of n
The above example doesn't generate prime numbers but tests them. You could adapt the same optimizations to your code :)
One of the more efficient algorithms I've found written in Python is found in the following question ans answer (using a sieve):
Simple Prime Generator in Python
My own adaptation of the sieve algorithm:
from itertools import islice
def primes():
if hasattr(primes, "D"):
D = primes.D
else:
primes.D = D = {}
def sieve():
q = 2
while True:
if q not in D:
yield q
D[q * q] = [q]
else:
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
return sieve()
print list(islice(primes(), 0, 1000000))
On my hardware I can generate the first million primes pretty quickly (given that this is written in Python):
prologic#daisy
Thu Apr 23 12:58:37
~/work/euler
$ time python foo.py > primes.txt
real 0m19.664s
user 0m19.453s
sys 0m0.241s
prologic#daisy
Thu Apr 23 12:59:01
~/work/euler
$ du -h primes.txt
8.9M primes.txt

Here is the standard method of generating primes adapted from the C# version at: Most Elegant Way to Generate Prime Number
def prime_gen(n):
primes = [2]
# start at 3 because 2 is already in the list
nextPrime = 3
while nextPrime < n:
isPrime = True
i = 0
# the optimization here is that you're checking from
# the number in the prime list to the square root of
# the number you're testing for primality
squareRoot = int(nextPrime ** .5)
while primes[i] <= squareRoot:
if nextPrime % primes[i] == 0:
isPrime = False
i += 1
if isPrime:
primes.append(nextPrime)
# only checking for odd numbers so add 2
nextPrime += 2
print primes

You start from this:
def prime_gen(n):
primes = [2]
a = 2
while a < n:
counter = 0
for i in primes:
if a % i == 0:
counter += 1
if counter == 0:
primes.append(a)
else:
counter = 0
a = a + 1
print primes
do you really need the else branch? No.
def prime_gen(n):
primes = [2]
a = 2
while a < n:
counter = 0
for i in primes:
if a % i == 0:
counter += 1
if counter == 0:
primes.append(a)
a = a + 1
print primes
Do you need the counter? No!
def prime_gen(n):
primes = [2]
a = 2
while a < n:
for i in primes:
if a % i == 0:
primes.append(a)
break
a = a + 1
print primes
Do you need to check for i larger that sqrt(a)? No.
def prime_gen(n):
primes = [2]
a = 3
while a < n:
sqrta = sqrt(a+1)
for i in primes:
if i >= sqrta:
break
if a % i == 0:
primes.append(a)
break
a = a + 1
print primes
Do you really want to manually increase a?
def prime_gen(n):
primes = [2]
for a in range(3,n):
sqrta = sqrt(a+1)
for i in primes:
if i >= sqrta:
break
if a % i == 0:
primes.append(a)
break
This is some basic refactoring that should automatically flow out of your fingers.
Then you test the refactored code, see that it is buggy and fix it:
def prime_gen(n):
primes = [2]
for a in range(3,n):
sqrta = sqrt(a+1)
isPrime = True
for i in primes:
if i >= sqrta:
break
if a % i == 0:
isPrime = False
break
if(isPrime):
primes.append(a)
return primes
And finally you get rid of the isPrime flag:
def prime_gen(n):
primes = [2]
for a in range(3,n):
sqrta = sqrt(a+1)
for i in primes:
if i >= sqrta:
primes.append(a)
break
if a % i == 0:
break
return primes
now you believe you're done. Then suddenly a friend of yours point out that for a even you are checking i >= sqrta for no reason. (Similarly for a mod 3 == 0 numbers, but then branch-prediction comes in help.)
Your friend suggest you to check a % i == 0 before:
def prime_gen(n):
primes = [2]
for a in range(3,n):
sqrta = sqrt(a+1)
for i in primes:
if a % i == 0:
break
if i >= sqrta:
primes.append(a)
break
return primes
now you're done and grateful to your brillant friend!

You can use Python yield statement to generate one item at the time. Son instead of get all items at once you will iterate over generator and get one item at the time. This minimizes your resources.
Here an example:
from math import sqrt
from typing import Generator
def gen(num: int) -> Generator[int, None, None]:
if 2 <= num:
yield 2
yield from (
i
for i in range(3, num + 1, 2)
if all(i % x != 0 for x in range(3, int(sqrt(i) + 1)))
)
for x in gen(100):
print(x, end=", ")
Output:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,

I made improvements on the solution proposed my jimifiki
import math #for finding the sqare root of the candidate number
def primes(n):
test = [3] #list of primes new candidates are tested against
found = [5] #list of found primes, which are not being tested against
c = 5 #candidate number, starting at five
while c < n: #upper bound, largest candidate will be this or 1 bigger
p = True #notes the possibility of c to be prime
c += 2 #increase candidate by 2, avoiding all even numbers
for a in test: #for each item in test
if c % a == 0: #check if candidate is divisible
p = False #since divisible cannot be prime
break #since divisible no need to continue checking
if p: #true only if not divisible
if found[0] > math.sqrt(c): #is samallest in found > sqrt of c
found.append(c) #if so c is a prime, add it to the list
else: #if not, it's equal and we need to start checking for it
test.append(found.pop(0)) #move pos 0 of found to last in test
return([2] + test + found) #after reaching limit returns 2 and both lists
The biggest improvement is not checking for even numbers and checking the square root only if the number is not divisible, the latter really adds up when numbers get bigger. The reason we don't need to check for the square root is, that the test list only contains numbers smaller than the square root. This is because we add the next number only when we get to the first non-prime not divisible by any of the numbers in test. This number is always the square of the next biggest prime which is also the smallest number in found. The use of the boolean "p" feels kind of spaghetty to me so there might be room for improvement.

Here's a pretty efficient prime number generator that I wrote a while back that uses the Sieve of Eratosthenes:
#!/usr/bin/env python2.7
def primeslt(n):
"""Finds all primes less than n"""
if n < 3:
return []
A = [True] * n
A[0], A[1] = False, False
for i in range(2, int(n**0.5)+1):
if A[i]:
j = i**2
while j < n:
A[j] = False
j += i
return [num for num in xrange(n) if A[num]]
def main():
i = ''
while not i.isdigit():
i = raw_input('Find all prime numbers less than... ')
print primeslt(int(i))
if __name__ == '__main__':
main()
The Wikipedia article (linked above) explains how it works better than I could, so I'm just going to recommend that you read that.

I have some optimizations for the first code which can be used when the argument is negative:
def is_prime(x):
if x <=1:
return False
else:
for n in xrange(2, int(x ** 0.5 + 1)):
if x % n == 0:
return False
return True
print is_prime(-3)

Being Python, it usually better to return a generator that will return an infinite sequence of primes rather than a list.
ActiveState has a list of older Sieve of Eratosthenes recipes
Here is one of them updated to Python 2.7 using itertools count with a step argument which did not exist when the original recipe was written:
import itertools as it
def sieve():
""" Generate an infinite sequence of prime numbers.
"""
yield 2
D = {}
for q in it.count(3, 2): # start at 3 and step by odds
p = D.pop(q, 0)
if p:
x = q + p
while x in D: x += p
D[x] = p # new composite found. Mark that
else:
yield q # q is a new prime since no composite was found
D[q*q] = 2*q
Since it is a generator, it is much more memory efficient than generating an entire list. Since it locates composite, it is computationally efficient as well.
Run this:
>>> g=sieve()
Then each subsequent call returns the next prime:
>>> next(g)
2
>>> next(g)
3
# etc
You can then get a list between boundaries (i.e., the Xth prime from the first to the X+Y prime...) by using islice:
>>> tgt=0
>>> tgt, list(it.islice(sieve(), tgt, tgt+10))
(0, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29])
>>> tgt=1000000
>>> tgt, list(it.islice(sieve(), tgt, tgt+10))
(1000000, [15485867, 15485917, 15485927, 15485933, 15485941, 15485959, 15485989, 15485993, 15486013, 15486041])

To Get the 100th prime number:
import itertools
n=100
x = (i for i in itertools.count(1) if all([i%d for d in xrange(2,i)]))
print list(itertools.islice(x,n-1,n))[0]
To get prime numbers till 100
import itertools
n=100
x = (i for i in xrange(1,n) if all([i%d for d in xrange(2,i)]))
for n in x:
print n

you can do it this way also to get the primes in a dictionary in python
def is_prime(a):
count = 0
counts = 0
k = dict()
for i in range(2, a - 1):
k[count] = a % i
count += 1
for j in range(len(k)):
if k[j] == 0:
counts += 1
if counts == 0:
return True
else:
return False
def find_prime(f, g):
prime = dict()
count = 0
for i in range(int(f), int(g)):
if is_prime(i) is True:
prime[count] = i
count += 1
return prime
a = find_prime(20,110)
print(a)
{0: 23, 1: 29, 2: 31, 3: 37, 4: 41, 5: 43, 6: 47, 7: 53, 8: 59, 9: 61, 10: 67, 11:
71, 12: 73, 13: 79, 14: 83, 15: 89, 16: 97, 17: 101, 18: 103, 19: 107, 20: 109}

Related

Need to find efficient method to find Strong number [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Written a program to find the find the Strong number
A number is considered to be a Strong number if sum of the factorial of its digits is equal to the number itself.
145 is a Strong number as 1! + 4! + 5! = 145.
Need to accept a list, find the Strong Number among the list and return a list of same
Ive tried :
def factorial(number):
if number == 0 or number == 1:
return 1
else :
return number * factorial(number - 1)
def find_strong_numbers(num_list):
sum = 0
ret_list = []
for i in num_list :
sum = 0
lst = list(map(int,list(str(i)))) #Converting the number into a list of numbers
for j in lst :
sum += factorial(j)
if sum == i :
ret_list.append(i)
return ret_list
num_list=[145,375,100,2,10]
strong_num_list=find_strong_numbers(num_list)
print(strong_num_list)
In the above example, I have created a list of the digits of the number and found its factorial.
But,
def factorial(number):
if number == 0 or number == 1:
return 1
else :
return number * factorial(number - 1)
def find_strong_numbers(num_list):
sum = 0
ret_list = []
for i in num_list :
sum = 0
lst = list(str(i)) #A List of Strings of the digits
for j in lst :
sum += factorial(int(j))
if sum == i :
ret_list.append(i)
return ret_list
num_list=[145,375,100,2,10]
strong_num_list=find_strong_numbers(num_list)
print(strong_num_list)
Ive created a list of Strings of Digits in the number
Converted the string to number when calling the factorial function.
This seems to be efficient for me as I need not to convert it into a map and then to int(less conversion)
Is this correct, is this efficient than the previous one or is there any far better optimised Code than this to find Strong Number.
You can simply memoize the factorial function to speed up the processing
from functools import lru_cache
#lru_cache(maxsize=128)
def factorial(number):
if number <= 1:
return 1
else:
return number * factorial(number - 1)
Also, you can use a generator to get the next digit like this
def get_next_digit(num):
while num:
yield num % 10
num //= 10
print(sum(factorial(digit) for digit in get_next_digit(145)))
This avoids creating an intermittent list of strings.
PS: These are minor optimisations which may not greatly improve the performance of the program.
Overall Code
from functools import lru_cache
#lru_cache(maxsize=128)
def factorial(number):
if number <= 1:
return 1
else:
return number * factorial(number - 1)
def get_next_digit(num):
while num:
yield num % 10
num //= 10
def is_strong_number(num):
return sum(factorial(digit) for digit in get_next_digit(num)) == num
def find_strong_numbers(num_list):
return [num for num in num_list if is_strong_number(num)]
num_list = [145, 375, 100, 2, 10]
print(find_strong_numbers(num_list))
Since you're only using factorials of 0..9, there's no need to have a function to compute them, let alone a recursive one. You can just hardcode all 10 values:
facts = {'0': 1, '1': 1, '2': 2, '3': 6, '4': 24, '5': 120, '6': 720, '7': 5040, '8': 40320, '9': 362880}
and then simply use:
def is_strong(n):
return sum(facts[s] for s in str(n)) == n
You can squeeze a bit more cycles of out this by avoiding a string conversion:
facts2 = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
def is_strong2(n):
s, k = 0, n
while k:
s += facts2[k % 10]
k //= 10
return s == n
...but given the fact that it's proven there are no such numbers beside 1, 2, 145, 40585, the whole enterprise looks a bit pointless ;)
Another version, using builtin math.factorial (doc):
from math import factorial
def is_strong_number(num):
return num == sum(factorial(int(c)) for c in str(num))
num_list=[145,375,100,2,10]
strong_num_list = [num for num in num_list if is_strong_number(num)]
print(strong_num_list)
Prints:
[145, 2]
others have already suggested improvements in their answers,
just for the sake of demonstrating a more empirical approach to runtime benchmarking:
you can use timeit to compare the runtime of different functions.
I added both of yours, and also a version that doesn't do the string<->int casting at all.
import timeit
def factorial(number):
if number == 0 or number == 1:
return 1
else:
return number * factorial(number - 1)
def find_strong_numbers_with_map(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
lst = list(map(int, list(str(i)))) # Converting the number into a list of numbers
for j in lst:
sum += factorial(j)
if sum == i:
ret_list.append(i)
return ret_list
def find_strong_numbers_cast_on_call(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
lst = list(str(i)) # A List of Strings of the digits
for j in lst:
sum += factorial(int(j))
if sum == i:
ret_list.append(i)
return ret_list
def find_strong_numbers_by_div_mod(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
while i > 0:
j = i % 10 # get the value of the last digit
sum += factorial(int(j))
i = i // 10 # "cut" the last digit from i
if sum == i:
ret_list.append(i)
return ret_list
num_list = [*range(1, 1000)]
print(timeit.timeit(lambda: find_strong_numbers_with_map(num_list), number=10 ** 3))
print(timeit.timeit(lambda: find_strong_numbers_cast_on_call(num_list), number=10 ** 3))
print(timeit.timeit(lambda: find_strong_numbers_by_div_mod(num_list), number=10 ** 3))
results on my laptop are:
2.4222552359969995
2.114583875001699
1.8628507399989758
There are several things you can do.
The first thing that comes to mind is making the factorial function iterative, instead of recursive:
def factorial(number):
if number == 0 or number == 1:
return 1
result = 1
for i in range(number + 1):
result *= i
return result
The second one would be to precompute all factorials for each digit, since there is a limited amount of them:
def get_factorials():
result = [1, 1]
value = 1
for i in range(2, 10):
value *= i
result.append(value)
return result
Then, instead of calling factorial each time, you could just do:
factorials = get_factorials()
lst = list(str(i))
for j in lst :
sum += factorials[int(j)]
Your result function could then be as simple as:
def is_strong_number(num):
return num == sum(map(lambda x: factorials[int(x)], str(num))
def find_strong_numbers(nums):
factorials = get_factorials()
return [num for num in nums if is_strong_number(num)]
Edit: thanks khelwood, fixed :)

How to make my program more efficient in Python

So I had to make a code which generates the first triangle number which has over 500 factors. The problem is given in detail below:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
I have written a block of code which generates the same however it is highly inefficient; kindly suggest some ways to improve it. Moreover it is so inefficient that it only works with numbers below 70
My code is given below, please refer:
def generates_triangle_numbers_upto_n(n):
list = [1]
while len(list)<n:
nth = int(len(list)+1)
to_be_appended = nth/2 + nth**2/2
list.append(to_be_appended)
return list
def return_number_of_n(n):
num = 0
for i in range(2, int(n)):
if n%i == 0:
num = num+1
return num + 2
def main(n):
list = generates_triangle_numbers_upto_n(20000)
for i in list:
if return_number_of_n(i) > int(n):
return i
print(main(100))
I saw a similar question on this site but I didn't understand how it worked:
Thanks a lot!
Edit 1: Thanks everyone for the wonderful suggestions, based on which I have refined my code:
def main(n):
list = [1]
while return_number_of_n_second(list[len(list)-1]) <= n:
nth = int(len(list)+1)
to_be_appended = int(nth/2 + nth**2/2)
list.append(to_be_appended)
return list[len(list)-1]
def return_number_of_n_second(n):
num = 0
import math
sqrt = math.sqrt(n)
for i in range(2, math.ceil(math.sqrt(n))):
if n%i == 0:
num = num+1
if int(sqrt) == sqrt:
return num*2 +3
return num*2 + 2
print(main(500))
However, now too, it takes 10-15 seconds to execute. Is there a way to make it even more efficient since almost all of project euler's problems are to be executed in 2-3 seconds max?
Just some basic technical optimizations and it should do it:
import time
import math
def main(n):
last, length = 1, 1
while return_number_of_n_second(last) <= n:
length += 1
last = int(length/2 * (length+1))
return last
def return_number_of_n_second(n):
sqrt = math.sqrt(n)
if int(sqrt) == sqrt:
return 2
return sum(1 for i in range(2, math.ceil(sqrt)) if not n % i) * 2 + 2
start_time = time.time()
print(main(500))
print(time.time() - start_time)

python prime numbers Sieve of Eratosthenes

Hi can anyone tell me how to implement Sieve of Eratosthenes within this code to make it fast? Help will be really appreciated if you can complete it with sieve. I am really having trouble doing this in this particular code.
#!/usr/bin/env python
import sys
T=10 #no of test cases
t=open(sys.argv[1],'r').readlines()
import math
def is_prime(n):
if n == 2:
return True
if n%2 == 0 or n <= 1:
return False
sqr = int(math.sqrt(n)) + 1
for divisor in range(3, sqr, 2):
if n%divisor == 0:
return False
return True
#first line of each test case
a=[1,4,7,10,13,16,19,22,25,28]
count=0
for i in a:
b=t[i].split(" ")
c=b[1].split("\n")[0]
b=b[0]
for k in xrange(int(b)):
d=t[i+1].split(" ")
e=t[i+2].split(" ")
for g in d:
for j in e:
try:
sum=int(g)+int(j)
p=is_prime(sum)
if p==True:
count+=1
print count
else:
pass
except:
try:
g=g.strip("\n")
sum=int(g)+int(j)
p=is_prime(sum)
if p==True:
count+=1
print count
else:
pass
except:
j=j.strip("\n")
sum=int(g)+int(j)
p=is_prime(sum)
if p==True:
count+=1
print count
else:
pass
print "Final count"+count
An old trick for speeding sieves in Python is to use fancy ;-) list slice notation, like below. This uses Python 3. Changes needed for Python 2 are noted in comments:
def sieve(n):
"Return all primes <= n."
np1 = n + 1
s = list(range(np1)) # leave off `list()` in Python 2
s[1] = 0
sqrtn = int(round(n**0.5))
for i in range(2, sqrtn + 1): # use `xrange()` in Python 2
if s[i]:
# next line: use `xrange()` in Python 2
s[i*i: np1: i] = [0] * len(range(i*i, np1, i))
return filter(None, s)
In Python 2 this returns a list; in Python 3 an iterator. Here under Python 3:
>>> list(sieve(20))
[2, 3, 5, 7, 11, 13, 17, 19]
>>> len(list(sieve(1000000)))
78498
Those both run in an eyeblink. Given that, here's how to build an is_prime function:
primes = set(sieve(the_max_integer_you_care_about))
def is_prime(n):
return n in primes
It's the set() part that makes it fast. Of course the function is so simple you'd probably want to write:
if n in primes:
directly instead of messing with:
if is_prime(n):
Both the original poster and the other solution posted here make the same mistake; if you use the modulo operator, or division in any form, your algorithm is trial division, not the Sieve of Eratosthenes, and will be far slower, O(n^2) instead of O(n log log n). Here is a simple Sieve of Eratosthenes in Python:
def primes(n): # sieve of eratosthenes
ps, sieve = [], [True] * (n + 1)
for p in range(2, n + 1):
if sieve[p]:
ps.append(p)
for i in range(p * p, n + 1, p):
sieve[i] = False
return ps
That should find all the primes less than a million in less than a second. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.
Fastest implementation I could think of
def sieve(maxNum):
yield 2
D, q = {}, 3
while q <= maxNum:
p = D.pop(q, 0)
if p:
x = q + p
while x in D: x += p
D[x] = p
else:
yield q
D[q*q] = 2*q
q += 2
raise StopIteration
Source: http://code.activestate.com/recipes/117119-sieve-of-eratosthenes/#c4
Replace this part
import math
def is_prime(n):
if n == 2:
return True
if n%2 == 0 or n <= 1:
return False
sqr = int(math.sqrt(n)) + 1
for divisor in range(3, sqr, 2):
if n%divisor == 0:
return False
return True
with
primes = [prime for prime in sieve(10000000)]
def is_prime(n):
return n in primes
Instead of 10000000 you can put whatever the maximum number till which you need prime numbers.
Here is a very fast generator with reduced memory usage.
def pgen(maxnum): # Sieve of Eratosthenes generator
yield 2
np_f = {}
for q in xrange(3, maxnum + 1, 2):
f = np_f.pop(q, None)
if f:
while f != np_f.setdefault(q+f, f):
q += f
else:
yield q
np = q*q
if np < maxnum: # does not add to dict beyond maxnum
np_f[np] = q+q
def is_prime(n):
return n in pgen(n)
>>> is_prime(541)
True
>>> is_prime(539)
False
>>> 83 in pgen(100)
True
>>> list(pgen(100)) # List prime numbers less than or equal to 100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97]
Here is a simple generator using only addition that does not pre-allocate memory. The sieve is only as large as the dictionary of primes and memory use grows only as needed.
def pgen(maxnum): # Sieve of Eratosthenes generator
pnext, ps = 2, {}
while pnext <= maxnum:
for p in ps:
while ps[p] < pnext:
ps[p] += p
if ps[p] == pnext:
break
else:
ps[pnext] = pnext
yield pnext
pnext += 1
def is_prime(n):
return n in pgen(n)
>>> is_prime(117)
>>> is_prime(117)
False
>>> 83 in pgen(83)
True
>>> list(pgen(100)) # List prime numbers less than or equal to 100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97]
This is a simple solution with sets.
Which is very fast in comparison with many of the list-algorithms.
Computation with sets is much faster because of the hash tables.
(What makes sets faster than lists in python?)
Greetings
----------------------------------
from math import *
def sievePrimes(n):
numbers = set()
numbers2 = set()
bound = round(sqrt(n))
for a in range(2, n+1):
numbers.add(a)
for i in range(2, n):
for b in range(1, bound):
if (i*(b+1)) in numbers2:
continue
numbers2.add(i*(b+1))
numbers = numbers - numbers2
print(sorted(numbers))
Simple Solution

Iterating until a function returns True a user defined number of times

I've written a function, isprime(n), that returns True if a number is prime and false if not.
I am able to loop the function a defined number of times; but I can't figure out how to iterate until it finds x number of primes. I feel as though I have a decent understanding of For and While loops, but am confused as to how one integrates boolean return values into loops. Here is my current code and error:
Error result:
input:100
Traceback (most recent call last):
File "euler7.py", line 25, in <module>
primeList += 1
TypeError: 'int' object is not iterable
And the code:
def isprime(n):
x = 2
while x < sqrt(n):
if n % x == 0:
return False
else:
x += 1
return True
userinput = int(raw_input('input:'))
primeList = []
primesFound = 0
while primesFound != userinput:
i = 2
if isprime(i):
primeList.append(i)
primeList += 1
i += 1
else:
i += 1
EDIT (including the updated and functioning code):
from math import sqrt
def isprime(n):
x = 2
while x < (sqrt(n) + 1):
if n % x == 0:
return False
else:
x += 1
return True
userinput = int(raw_input('input:'))
primeList = []
primeList.append(2)
i = 2
while len(primeList) != userinput:
if isprime(i):
primeList.append(i)
i += 1
else:
i += 1
print 'result:', primeList[-1]
This line:
primeList += 1
Should be:
primesFound += 1
You cannot add and int to a python list. You should do primesFound += 1 to achieve your desired result.
Plus, your isprime function is wrong. It will return True for 9. You should do while x < sqrt(n) + 1 for the while loop of your isprime function.
So you should have:
def isprime(n):
x=2
while x < sqrt(n) +1:
if n % x == 0:
return False
else:
x += 1
return True
As others have pointed out:
You should increment primesFound, not primeList.
The isprime() function has a bug -- and returns True for 9. You need sqrt(n) + 1.
In addition:
You need to initialize i outside the while loop; otherwise, you simply build up a list of 2's.
There is no need for primesFound. Just check len(primeList).
And my pet peeve:
Command-line programs should resort to interactive user input only in special circumstances. Where possible, take parameters as command-line arguments or options. For example: userinput = int(sys.argv[1]).
To get n numbers that satisfy some condition, you could use itertools.islice() function and a generator expression:
from itertools import count, islice
n = int(raw_input('number of primes:'))
primes = list(islice((p for p in count(2) if isprime(p)), n))
where (p for p in count(2) if isprime(p)) is a generator expression that produces prime numbers indefinitely (it could also be written as itertools.ifilter(isprime, count(2))).
You could use Sieve of Eratosthenes algorithm, to get a more efficient solution:
def primes_upto(limit):
"""Yield prime numbers less than `limit`."""
isprime = [True] * limit
for n in xrange(2, limit):
if isprime[n]:
yield n
for m in xrange(n*n, limit, n): # mark multiples of n as composites
isprime[m] = False
print list(primes_upto(60))
# -> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
See Fastest way to list all primes below N in python.
Note: there are about limit / (log(limit) - 1) prime numbers less than limit.
You could also use an infinite prime number generator such as gen_primes(), to get the first n primes numbers:
primes = list(islice(gen_primes(), n))
See How to implement an efficient infinite generator of prime numbers in Python?
def is_prime(n):
x=2
while x < sqrt(n) +1:
if n % x == 0:
return False
break
else:
x += 1
return True

Range is too large Python

I'm trying to find the largest prime factor of the number x, Python gives me the error that the range is too large. I've tried using x range but I get an OverflowError: Python int too large to convert to C long
x = 600851475143
maxPrime = 0
for i in range(x):
isItPrime = True
if (x%i == 0):
for prime in range(2,i-1):
if (i%prime == 0):
isItPrime = False
if (isItPrime == True):
if (i > maxPrime):
maxPrime = i;
print maxPrime
In old (2.x) versions of Python, xrange can only handle Python 2.x ints, which are bound by the native long integer size of your platform. Additionally, range allocates a list with all numbers beforehand on Python 2.x, and is therefore unsuitable for large arguments.
You can either switch to 3.x (recommended), or a platform where long int (in C) is 64 bit long, or use the following drop-in:
import itertools
range = lambda stop: iter(itertools.count().next, stop)
Equivalently, in a plain form:
def range(stop):
i = 0
while i < stop:
yield i
i += 1
This is what I would do:
def prime_factors(x):
factors = []
while x % 2 == 0:
factors.append(2)
x /= 2
i = 3
while i * i <= x:
while x % i == 0:
x /= i
factors.append(i)
i += 2
if x > 1:
factors.append(x)
return factors
>>> prime_factors(600851475143)
[71, 839, 1471, 6857]
It's pretty fast and I think it's right. It's pretty simple to take the max of the factors found.
2017-11-08
Returning to this 5 years later, I would use yield and yield from plus faster counting over the prime range:
def prime_factors(x):
def diver(x, i):
j = 0
while x % i == 0:
x //= i
j += 1
return x, [i] * j
for i in [2, 3]:
x, vals = diver(x, i)
yield from vals
i = 5
d = {5: 2, 1: 4}
while i * i <= x:
x, vals = diver(x, i)
yield from vals
i += d[i % 6]
if x > 1:
yield x
list(prime_factors(600851475143))
The dict {5: 2, 1: 4} uses the fact that you don't have to look at all odd numbers. Above 3, all numbers x % 6 == 3 are multiples of 3, so you need to look at only x % 6 == 1 and x % 6 == 5, and you can hop between these by alternately adding 2 and 4, starting from 5.
The accepted answer suggests a drop-in replacement for xrange, but only covers one case. Here is a more general drop-in replacement.
def custom_range(start=0,stop=None,step=1):
'''xrange in python 2.7 fails on numbers larger than C longs.
we write a custom version'''
if stop is None:
#handle single argument case. ugly...
stop = start
start = 0
i = start
while i < stop:
yield i
i += step
xrange=custom_range
I would definitely stick with xrange since creating a list between 0 and what looks like a number rivaled by infinity would be taxing for memory. xrange will generate only the numbers when asked. For the number too large problem, you might want to try a "long". This can be achieved by writing a L on the end of the number. I made my own version to test it out. I put in a small sleep as to not destroy my computer into virtually a while(1) loop. I was also impatient to see the program come to a complete end, so I put in print statements
from time import sleep
x = 600851475143L
maxPrime = 0
for i in xrange(1,x):
isItPrime = True
if (x%i) == 0:
for prime in xrange(2,i-1):
if (i%prime) == 0:
isItPrime = False
break
if isItPrime:
maxPrime = i
print "Found a prime: "+str(i)
sleep(0.0000001)
print maxPrime
Hope this helps!
EDIT:
I also did a few more edits to yield this version. It is fairly efficient and I checked quite a few numbers this program provides (it seems to check out so far):
from time import sleep
x = 600851475143L
primes = []
for i in xrange(2,x):
isItPrime = True
for prime in primes:
if (i%prime) == 0:
isItPrime = False
break
if isItPrime:
primes.append(i)
print "Found a prime: "+str(i)
sleep(0.0000001)
print primes[-1]
Very uneficient code, that's not the best way of getting dividers, I've done it with a for and range, but I can't execute it because of the long variables, so I decided to implement it with a for using a while, and increment a counter by myself.
For 32 bit int like 13195:
# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?
i = 13195
for j in xrange(2, i, 1):
if i%j == 0:
i = i/j
print j
Good way for longer numbers:
# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?
i = 600851475143
j = 2
while i >= j:
if i%j == 0:
i = i/j
print j
j = j+1
The last prime is the last printed value.
Another implementation for python 2 range():
import itertools
import operator
def range(*args):
"""Replace range() builtin with an iterator version."""
if len(args) == 0:
raise TypeError('range() expected 1 arguments, got 0')
start, stop, step = 0, args[0], 1
if len(args) == 2: start, stop = args
if len(args) == 3: start, stop, step = args
if step == 0:
raise ValueError('range() arg 3 must not be zero')
iters = itertools.count(start, step)
pred = operator.__ge__ if step > 0 else operator.__le__
for n in iters:
if pred(n, stop): break
yield n

Categories