How does a Sieve of Eratosthenes work in this code? - python

I need some help explaining the Sieve of Eratosthenes below. I copied it from some other Stackoverflow page, but I do not understand it line by line. Can someone explain this?
def eratosthenes(n):
multiples = []
for i in range(2, n):
if i not in multiples:
print (i)
for j in range(i*i, n, i): #Troubled Part
multiples.append(j)
eratosthenes(100)
I especially do not get the range(i*i...) part. Why are there three attributes in one set of parentheses? Also, why is i squared? Thanks!

Let's go line by line:
multiples = [] makes a list of composite numbers, we'll add here later
for i in range (2,n) we're looping from 2 to n, trying to get all of the primes.
if i not in multiples we're checking if i is a composite number that we've already found
print(i) Well i must be prime, so let's print it out
for j in range(i*i,n,i) Count by is, from i*i to n, as each of these numbers will be a composite number. Note that we're going from i*i, as numbers like i*[number<i] will have been recorded from previous iterations
multiples.append(j) add j to the list of the composite numbers

The third attribute in the range is just an increment. It is saying add i to i*i until we reach n.
So the Sieve of Eratosthenes works by getting rid of multiples of primes (i.e. composites, which are tracked in the multiples list) as we go forward, so like [2,4,6,8,...], [3,9,12,...],[5,25,30,...] as we go on.
In the first of each of the above sequences, we have the prime number, the subsequent elements in the sequence are added to the multiples list
The part where you've highlighted:
for j in range(i*i, n, i): #Troubled Part
multiples.append(j)
This is just adding all the composite multiples of the prime numbers. To be more explicit, let's look at 2.
2 is not in multiples. So it is printed. Then let's think concretely about what happens next:
for j in range(2*2, 100, 2)
This will add 4, 6, 8, 10, and so forth to the multiples list, which are the numbers we ignore because they are composites. You can think of i*i as simply the next element in the sequence of multiples that we start at.
In this way, we continue for 3, starting from 9, 12, 15, and so forth.
Notice that the composite numbers 4,6,8 had already been excluded in the first iteration, so that is why we can start at 9 and continue.
This is in fact a significant point that Ryan Fu has pointed out.
So to put this in the clearest terms:
2 is printed. The multiple list is updated with all other even numbers [4,6,8,10,...]
We go to 3 next because it is not in multiples. We add [9,12,15,18,21,...] to the list.
Notice that we do not need to bother adding 6 to the list because it was already previously added when we considered 2. This is why we do not need to do something like
for j in range(i*2, n, i)
The process continues, the next number we have is 5, so [25,30,35,40,...] are added to multiples
Eventually only the primes are printed.

multiples is storing all the multiple of a prime no for eg for 2 is prime no then 4,6,8,10,12... are multiple of and not primes and there is no need to check these no as they are prime or not at we know that they are not.
if i not in multiple indicate that i is prime number, and then we are saving all the multiple of i. in your solution i think there is no need to use i*i in for j in range(i*i, n , i) but 2*i would be right choice ie for j in range(2*i, n, i) and multiples should be of type set not list as this would allow duplicates and search time complexity would be O(N) in list case and O(1) in set case.
def eratosthenes(n):
multiples = set()
for i in range(2, n):
if i not in multiples:
print (i)
for j in range(2*i, n, i): #Troubled Part
multiples.add(j)
eratosthenes(100)

Related

My python program won't execute or show anything in the terminal

So I was trying to solve a project Euler question that asks we shoud find the largest prime factor of 600851475143.
This is my code:
factors = [i for i in range(1,600851475144) if 600851475143%i is 0]
prime_factors = []
for num in factors:
factors_of_num = [i for i in range(1, num+1) if num%i is 0]
if factors_of_num == [1, num]:
prime_factors.append(num)
print(max(prime_factors))
The issue is that this code won't run for a large number like this. How can \i get this to work?
Your program is executing, but range(1, 600851475144) is just taking a rrrrrrrrrrrrrrrrrrrrrrrreally long time. There are much better ways to get prime factors instead of first checking each number individually whether it is a divisor and then checking which of those are primes.
First, for each pair of divisors p * q = n, either p or q has to be <= sqrt(n), so you'd in fact only have to check the numbers in range(1, 775147) to get one part of those pairs and get the other for free. This alone should be enough to make your program finish in time. But you'd still get all the divisors, and then have to check which of those are prime.
Next, you do not actually have to get all the prime factors of those divisors to determine whether those are prime: You can use any to stop as soon as you find the first non-primitive factor. And here, too, testing up to sqrt(num) is enough. (Also, you could start with the largest divisor, so you can stop the loop as soon as you find the first one that's prime.)
Alternatively, as soon as you find a divisor, divide the target number by that divisor until it can not be divided any more, then continue with the new, smaller target number and the next potential divisor. This way, all your divisors are guaranteed to be prime (otherwise the number would already have been reduced by its prime factors), and you will also need much fewer tests (unless the number itself is prime).

PYTHON: Finding an nth prime number

I've looked through a variety of older posts on this subject, and they have all left me confused in some way or another. So I'll start at the beginning.
The problem is #7 on Project Euler and I am a fairly new programmer trying to work my way through the problems. #7 is as follows.
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
What is the 10,001st prime number?
My issue is as follows. I have a clear understanding of what prime numbers are and how they work. The sudo-code I would write for this problem is this:
For n in range(3,n) #where n is some very large value.
if n%i ==0 for i in range(2,n-1)
return False
if n%i == 0 for i == n
return True
But I think my lack of knowledge when it comes to Python is impeding me in finding what I want.
In most of the other solutions I have seen, they limit n to something like 125000 and I honestly have no clue where they came up with that number from.
The other issue is I don't know how to search properly through a range and create a list of values that satisfied that relation in a manner that I can then check the Max value in the list.
The thing that would make the most sense to me would be to basically append each new prime to a list and then just take the max value, but I'm sure there is a better and faster way to do this. If you are going to answer, please include a healthy dose of explanation without jumping into python technobabble, remember, I'm a beginner in programming.
I know that the typical way people deal with questions like this is to prod the asker into finding the right answer, I don't want that. I would like someone to show me a solution and then walk through it step by step explaining what each part of the code does so that I can learn not only how to solve the problem, but also gain a better intuition for how python works.
Thanks.
This task basically asks you to gather 10001 prime numbers. So start by building a list of primes and when you reach the 10001th number display it.
Here is a sample code:
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
primes = [] # list of primes
x = 10001 # go to the nth-number
n = 2 # start at number 2
while len(primes) != x+1: # is n-th number on the list? +1 is because list is zero-based
if is_prime(n):
primes.append(n) # add prime to the list
n+=1 # increment n to check the next number
# print the last item in the list - the n-th number
print(primes[-1])

Efficient method for generating lists of large prime numbers

What I'm trying to figure out is when I run this code for smaller numbers it returns the list just fine, but for larger numbers (I would call this small in the context of what I'm working on.) like 29996299, it will run for a long time, I've waited for 45 minutes with no results and had to end up killing the program. What I was wondering was whether there was a more efficient way to handle numbers whose scale was larger than 4 or 5 digits. I've tested a few permutations of the range function to see if there was a better way to handle the limits of the list I want to produce but nothing seems to have any effect on the amount of time it takes to do the computation. I'm new to python and am not that experienced as a programmer. Thank you for your time.
ran the program again before submitting this post and it took an hour and a half or so.
function of the program is to take the User selected number, use it to generate a lower bound, find all primes between the bound and input and append to list, then generate a secound upper bound and find all primes and then append to list, to create a list that extends forwards and backwards from the initial number.
the program works like I expect it to but not as quickly as I need it to since the numbers I'm going to be dealing with are going to get large quickly, almost doubling at each phase.
initial_num = input("Please enter a number. ")
lower_1 = int(initial_num) - 1000
upper_1 = int(initial_num)
list_1 = []
for num in range(lower_1,upper_1):
if num > 1:
for i in range(2,num):
if (num % i) == 0:
break
else:
list_1.append(num)
lower_2 = list_1[-1]
upper_2 = list_1[-1] + 2000
list_2 = []
for num in range(lower_2,upper_2 +1):
if num > 1:
for i in range(2,num):
if (num % i) == 0:
break
else:
list_2.append(num)
list_3 = list_1 + list_2[1:]
print list_3
You can use a more efficient algorithm to generate the entire list of prime numbers up to N. This is the Sieve of Erathostenes. Please have a look at the linked article, it even includes an example pseudocode. The basic idea of the algorithm is:
maintain L, a list of potentially prime numbers (initially all numbers from 2 to N)
pick the next prime number (p) as the first element of L (intially 2)
remove all numbers that are a multiple of p, up to N, since they cannot be prime
repeat from step 2
At the end you are left with a list of prime numbers.
An implementation in Pyhton from here
def eratosthenes2(n):
multiples = set()
for i in range(2, n+1):
if i not in multiples:
yield i
multiples.update(range(i*i, n+1, i))
print(list(eratosthenes2(100)))
To reduce memory consumpution you could consider usgin a bitset, storing one bit for each number. That should reduce memory usage by between 32 - 64 times. A bitset implementation is available for python here.

Sieve of Eratosthenes in Python

I am trying to write a python function to return the number of primes less than a given value and the values of all the primes. I need to use the Sieve of Eratosthenes algorithm. I believe I'm missing something in the function - For example, when I want to find the primes under 100. All I got is 2, 3, 5, 7. I am aware that if I don't use "square root", I can get all the primes I need; but I am told that I need to include square root there. Can someone please take a look at my code and let me know what I am missing? Thanks for your time.
def p(n):
is_p=[False]*2 + [True]*(n-1)
for i in range(2, int(n**0.5)):
if is_p[i]:
yield i
for j in range(i*i, n, i):
is_p[j] = False
"I am told I need to use square root". Why do you think that is? Usually the sieve of E. is used to remove all "non prime" numbers from a list; you can do this by finding a prime number, then checking off all multiples of that prime in your list. The next number "not checked off" is your next prime - you report it (with yield), then continue checking off again. You only need to check for factors less than the square root - factors greater than the square root have a corresponding factor less than the square root, so they have alread been found.
Unfortunately, when it comes to printing out the primes, you can't "stop in the middle". For example, 101 is prime; but if you only loop until 11, you will never discover that it's there. So there need to be two steps:
1) loop over all "possible multiples" - here you can go "only up to the square root"
2) check the list for all numbers that haven't been checked off - here you have to "go all the way"
This makes the following code:
def p(n):
is_p=[False]*2 + [True]*(n-1)
for i in range(2, int(n**0.5)):
if is_p[i]:
for j in range(i*i, n, i):
is_p[j] = False
for i in range(2, n):
if is_p[i]:
yield i
print list(p(102))
The result is a list of primes up to and including 101.
Your logic is correct, except for the for loop. It terminates after reaching sqrt(n)-1. For p(100), it will run only from 2 to 9. Hence you get prime numbers only till 9.
Your use of the square root is terminating your results early. If you want to yield all the primes up to 100, your loop has to go to 100.
The square root isn't necessary in your code because it's implied in your second for loop. If i*i < n then i < sqrt(n).

Python - Check if numbers in list are factors of a number

I have a list of numbers (integers) (say, from 1 to 10).
They're not necessarily consecutive, but they are in ascending order.
I've prompted the user multiple times to enter a choice of the available numbers. When that number is entered, it is removed from the list along with any of its factors that may be there.
I've prevented the user from selecting prime numbers. However, at some point in time, there may be non-prime numbers there, which have no factors remaining.
I'm relatively new to Python, so I'm having trouble implementing:
Checking if the number selected has no factors remaining (even if it is not prime).
Checking if only prime numbers remain, or numbers without
factors.
I'm thinking of using for statements, but I'm not sure exactly how to implement them. Can anyone offer advice, or code? Thanks in advance...
To check if there are any factors of the number guess remaining you can use any():
hasfactors = any(guess % n == 0 for n in numbers)
To check if all the remaining numbers are prime, all() can be used. (Since you say you already prevented the user from inputting prime numbers I assume you have some kind of isprime() function):
onlyprimes = all(isprime(n) for n in numbers)
For the first problem, you could use list comprehensions to build a new list where each element is not the number selected and not a factor of the number selected (see code). Compare this with your original list.
$ python
>>> selected_number = 6
>>> [x for x in range(1,11) if selected_number % x]
[4, 5, 7, 8, 9, 10]
For the second problem, check if each element is prime. If not, check for numbers without factors; for each element, you might mod over the original list and check if it's a list of zeros. I'm sure there's a faster way, though.
If L is a list of non-zero numbers, the list of those which are factors of a number N is:
factors = [x for x in L if N % x == 0]
The list will simply be empty if N has no factors in L, of course.
I'm not sure what you mean by "numbers without factors", unless you mean "primes" (?) -- there have been several SO questions and answers on checking primality in Python, I'd use gmpy.is_prime (from my extension gmpy) but then of course I'm biased;-).
If you mean, "all numbers that have no factors in L", well, there's infinitely many of them, so it's kind of hard to make a list of them all. An unbounded generator for them:
import itertools
def nofactorsinlist(L):
for i in itertools.count():
if any(x for x in L if i % x == 0):
continue
yield i
Some optimizations would be possible, but this one is really simple and I'm loath to add complicated optimizations without understanding exactly what it is that you're after!-)

Categories