PYTHON: Finding an nth prime number - python

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])

Related

Debugging in Hungarian Maximum Matching

I wrote a code to solve the following algorithm question:
Given a number of positive integers all larger than 1, find the maximum number of pairs whose sum is a prime number. The number of positive integers is always an even number.
For example, given 2 5 6 13 2 11, the answer is 3 since 2+5=7, 6+13=19, 2+11=13.
I wrote the following code to solve the problem. I know this is not the optimal algorithm, but I just cannot find the bug in it that results in my failure in test cases.
def _isPrime(num):
for i in range(2, int(num**0.5)+1):
if num % i==0:
return False
return True
def findPairs(odds, evens, pairDict):
if len(odds)==0 or len(evens)==0:
return 0
key=' '.join(list(map(str, odds+evens)))
if key in pairDict:
return pairDict[key]
n=0
for i in range(len(evens)):
newOdds=odds.copy()
newEvens=evens.copy()
del newOdds[0]
del newEvens[i]
if _isPrime(odds[0]+evens[i]):
n=max(n,findPairs(newOdds, newEvens, pairDict)+1)
else:
n=max(n,findPairs(newOdds, newEvens,pairDict))
pairDict[key]=n
return n
numbers=list(map(int,input().split()))
odds=[i for i in numbers if i%2==1]
evens=[j for j in numbers if j%2==0]
pairDict={}
print(findPairs(odds,evens,pairDict))
Can someone help me find where the problem is. Thanks a lot!
The problem is that the recursion always tries to match the first odd number with some even number. This can go wrong if there are fewer even numbers than odd numbers because it will use up an even number that could have been used for a later match.
For example, consider "13 2 3". This code will return 0, but 2+3 is a prime.
You could fix it by also allowing an extra recursion case where the first odd number is discarded without reducing the even list.
del newOdds[0]
n=max(n,findPairs(newOdds, newEvens, pairDict)) # added line
del newEvens[i]

Optimising code for finding the next prime number

I'm new to both Python and StackOverflow so I apologise if this question has been repeated too much or if it's not a good question. I'm doing a beginner's Python course and one of the tasks I have to do is to make a function that finds the next prime number after a given input. This is what I have so far:
def nextPrime(n):
num = n + 1
for i in range(1, 500):
for j in range(2, num):
if num%j == 0:
num = num + 1
return num
When I run it on the site's IDE, it's fine and everything works well but then when I submit the task, it says the runtime was too long and that I should optimise my code. But I'm not really sure how to do this, so would it be possible to get some feedback or any suggestions on how to make it run faster?
When your function finds the answer, it will continue checking the same number hundreds of times. This is why it is taking so long. Also, when you increase num, you should break out of the nested loop to that the new number is checked against the small factors first (which is more likely to eliminate it and would accelerate progress).
To make this simpler and more efficient, you should break down your problem in areas of concern. Checking if a number is prime or not should be implemented in its own separate function. This will make the code of your nextPrime() function much simpler:
def nextPrime(n):
n += 1
while not isPrime(n): n += 1
return n
Now you only need to implement an efficient isPrime() function:
def isPrime(x):
p,inc = 2,1
while p*p <= x:
if x % p == 0: return False
p,inc = p+inc,2
return x > 1
Looping from 1 to 500, especially because another loop runs through it, is not only inefficient, but also confines the range of the possible "next prime number" that you're trying to find. Therefore, you should make use of while loop and break which can be used to break out of the loop whenever you have found the prime number (of course, if it's stated that the number is less than 501 in the prompt, your approach totally makes sense).
Furthermore, you can make use of the fact that you only need check the integers less than or equal to the square root of the designated integer (which in python, is represented as num**0.5) to determine if that integer is prime, as the divisors of the integers always come in pair and the largest of the smaller divisor is always a square root, if it exists.

what is the highest prime number between 1 and 10001

So I'm trying to find the 10,001 prime number. Yes, its the euler #7 problem. The code i wrote appears to give me all the prime numbers from 3 to 10,001 but my answer is still incorrect. I know there are other questions about this that have been answered but stealing someone else code does not help me learn. So I'm looking for insight into where i went wrong with this. First I seperated out all the odd numbers and added them to a list. I noticed that there were squares of some of the prime numbers in the list so I check the list against the squares of every number from 2 to 10,0001. That should have left me with nothing but prime numbers but I am still getting the wrong answer. Any ideas would be great thank you
prime = [i for i in range(2, 10002) if i % 2 != 0]
for i in range(2, 10002):
if i * i in prime:
prime.remove(i * i)
print(prime[-1])
Have you tried the case of 7*11=77? You're only looking in perfect squares when you should search multiples of all the known primes. In keeping with the theme of Project Euler, I'm not gonna give you the answer, but I_ can_ point you to the Sieve of Eratosthenes.
well actually... Since it's such an early problem, I'll dangle a spoiler.
Make a list of primes, initialize it to [2,3,5]. Starting from n=8 and increasing by six each time, check n-1 and n+1 for primality by testing modulos for each known primes from 2 to the square root of your number.

Solution to Euler Project Task 5: Why does it work?

After some trial and error I have found a solution which works very quickly for the Project Euler Problem 5. (I have found another way which correctly solved the example case (numbers 1-10) but took an eternity to solve the actual Problem.) Here it goes:
def test(n):
for x in range(2,21):
if n % x != 0:
return False
return True
def thwart(n):
for x in range(2,21):
if test(n/x):
n /= x
return n
raise TypeError
num = 1
for x in range(1,21):
num *= x
while True:
try:
num = thwart(num)
except TypeError:
break
print(num)
My main problem is understanding why calling thwart(num) repeatedly is enough to result in the correct solution. (I.e. why is it able to find the SMALLEST number and doesnt just spit out any number divisible by the numbers 1-20?)
I only had some vague thoughts when programming it and was surprised at how quickly it worked. But now I have trouble figuring out why exactly it even works... The optimized solutions of other people on SO Ive found so far were all talking about prime factors which I can't see how that would fit with my program...?
Any help is appreciated! Thanks!
Well this isn't really a coding issue but a mathematical issue. If you look at all the numbers from 1-20 as the prime sthat make them you'll get the following:
1, 2,3,2^2,5,2^3,7,2^3....2^2*5.
the interesting part here is that once you multiply by the highest exponent of every single factor in these numbers you will get a number that can be divided by each of the numbers between one and twenty.
Once you realize that the problem is a simple mathematical one and approach it as such you can use this basic code:
import math
primes = [2]
for n in range(3,21): #get primes between 1 and 20
for i in primes:
if n in primes:
break
if n%i == 0:
break
if i> math.sqrt(n):
primes.append(n)
break
s = 1
for i in primes:
for j in range(10): # no reason for 10, could as well be 5 because 2^5 >20
if i**j > 20:
s = s*(i**(j-1))
break
print s
Additionally, the hint that the number 2520 is the smallest number that can be divided by all numbers should make you understand how 2520 is chosen:
I have taken a photo for you:
As you can caculate, when you take the biggest exponents and multiply them you get the number 2520.
What your solution does
your solution basically takes the number which is 1*2*3*4..*20 and tries dividing it by every number between 2 to 20 in such a way that it will still remain relevant. By running it over and over you remove the un-needed numbers from it. early on it will remove all the unnecessary 2's by dividing by 2, returning the number and then being called again and divided by 2 again. Once all the two's have been eliminated it will eliminate all the threes, once all the unnecessary threes will be eliminated it will try dividing by 4 and it will se it wont work, continue to 5, 6, 7... and when it finishes the loop without being able to divide it will raise a TypeError and you will finish your program with the correct number. This is not an efficient way to solve this problem but it will work with small numbers.

Project Euler #35: nicer way to test if an even integer is 'inside' an integer

Question: What's the best way to iterate over an integer and find other integers inside it, then throw that integer away if it contains them?
Long Version:
I have been working on my Python skills by trying to make efficient solutions to the problems at Project Euler. After going through around 20 problems, I find that while I can solve the problems my solutions are often inelegant and clunky (i.e., ugly and slow). The way the problems are structured, I think I need to learn some better solutions because more complex stuff is going to compound these inefficiencies.
Anyway, today I'm working on problem 35, which requests all circular primes below 1,000,000. I have produced a list of all primes below 1,000,000 and I built a little framework to spit out permutations of these primes below, for each of which I was planning to test for prime-ness:
def number_switcher(number):
number = [num for num in str(number)]
numlist = [''.join(num) for num in list(itertools.permutations(number))]
return [int(num) for num in numlist]
Running this on all the primes and then testing each possible permutation for prime-ness, as you can imagine, is no way to solve the problem.
Then it occurred to me that I could throw away all numbers that have an even number in them (assuming they're longer than one digit) or any numbers with fives in them before I even start running the permutations.
Here's where I really got lost. Even though it seems simple, I can't figure out after two days of trying, how to throw away any multi-digit number with an even number or a 5 inside of it.
Here's what I tried (assuming a list of all primes below 1,000,000 called here "primes"):
[num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable
Then I experimented with the following:
for prime in primes:
if '0' in str(prime):
primes.remove(prime)
>>>>len(primes)
4264
This cut my primes list about in half. Okay, so maybe I'm on the right track and I just need an ugly "if '0' in str(prime) or if '2' in str(prime)," etc.
But here's the weird thing: when I examine my 'primes' list, it still has primes with '0's in it. Running the same thing again on the new list of primes, I get the following results:
for prime in primes:
if '0' in str(prime):
primes.remove(prime)
>>>>len(primes)
4026
...and again the result drops to:
>>>>len(primes)
3892
....
3861 # again
....
3843 #and again
Maybe I'm missing something obvious here, but it seemed like that first if-test should find any prime with '0' in it and remove all of them?
Lastly, I also tried the following, which seems terrible because it jumps pointlessly back and forth across the str-integer train tracks, but it seemed like it just had to work:
for num in primes:
for d in str(num):
if (int(d) % 2 == 0 or int(d) == 5):
primes.remove(num) # doesn't work: ValueError: list.remove(x): x not in list
else:
pass
I feel like I shouldn't be tearing my hair out over this question, but it's making me a little crazy and probably because I've gotten to a point where I'm just trying to hack out a solution, my attempts are getting less lucid.
Here's my question:
What's the best way to iterate over an integer and find other integers inside it, then throw that stupid integer away if it contains them?
Thanks for your help/reading.
Footnote:
This is the first question I have asked here but I have benefitted from this site's guidance for a few months now. Apologies if this question/solution is extant, but I looked for it and could not find a way to cobble together a solution. Most search results come up as "how to tell if an integer is even".
#root is correct that your assumption about how to optimise this is false, but I'd thought it'd be useful to point out why what you're doing isn't working on a Python level.
Your bool problem:
[num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable
'024685' in str(num) is being evaluated first, so it equates to for x in True - which isn't possible. The above would be written as:
[num for num in primes if not any(ch in '024685' for ch in str(num)]
Which takes each character from str(num) and checks to see if it's one of '024685'.
Your list problem:
There's a rule of thumb here - don't modify something you're iterating over. If you were to try this with a dict you'd get an exception thrown - but for a list it's likely to get silently wrong, but occasionally will break.
When removing more than one value from a list, it's better to build a new list keeping only the required values, eg:
no_zero = [num for num in primes if '0' not in str(num)]
And if you wanted to modify the original primes:
primes[:] = no_zero
Your last example also fails because of .remove(), and putting the above together can be written as:
[num for num in primes if not any(num % i == 0 for i in (2, 5)]
Misc:
You may wish to consider storing the primes in a set - as you're not concerned about the order of the primes, and will be faster for membership testing.
Thanks, Jon Clements. I was able to solve the problem today with the following script (note that I had to make sure the '024685' stripper did not strip out '2' and '5' because those were part of the answer, which threw me off for awhile...):
import math
import itertools
def prime_test(number):
if all(number % x != 0 for x in range(2, int(math.sqrt(number)) + 1)):
return True
else:
return False
def find_primes(limit):
primes = [2]
for x in range(3, limit + 1, 2):
if prime_test(x):
primes.append(x)
else:
pass
return primes
def circulate(number):
circ_list = [number]
x = 1
while x < len(str(number)):
number = str(number)[1:] + str(number)[0]
circ_list.append(number)
x += 1
return circ_list
def main():
primes = find_primes(1000000)
no_evens = [x for x in primes if not any(ch in '024685' for ch in str(x) if len(str(x)) > 1)]
circular_primes = []
for prime in no_evens:
if all(prime_test(x) for x in circulate(prime)):
circular_primes.append(prime)
else:
pass
return circular_primes, len(circular_primes)
if __name__ == '__main__':
print(main())
Another thing I didn't realize is that I was merely supposed to rotate the number, not provide all possible permutations of it. These gotches probably throw people off when they're trying to solve the problem.

Categories