Finding nth Palindromic Prime - Where did I go wrong? - python

Given integer n (1<=n <=300), the code needs to return the nth Palindromic Prime.
I have written the below block of code to achieve the above, but for the life of me I cannot understand why my code isn't outputting the given expected value.
Indeed I don't even know if it is my code that is wrong, or the given expected value is just bull. Would really appreciate some guidance.
Expected output: symmetricPrime2(72) returns 70507
Actual output: symmetricPrime2(72) returns 30103
def symmetricPrime2(n,candidate=2):
primes = [2]
counter = 1
while True:
i = 0
prep = 0
candidate = candidate + 1
candidate_sr = str(candidate)
#test if candidate is prime
for prime in primes:
if candidate%prime == 0:
prep += 1
#test if candidate is palindromic
candidate_sr_rev = candidate_sr[len(candidate_sr)::-1]
if prep == 0 and candidate_sr == candidate_sr_rev:
primes.append(candidate)
if len(primes) == n:
break
return primes[-1]

You're testing numbers for primality based on whether or not they are divisible by numbers in the primes list, but you only add numbers to primes if they are palindromic. As a result, once you start encountering composite numbers with prime factors greater than 11, you're going to start identifying primes incorrectly.
According to your function, symmetricPrime2(12) == 323, but 323 is composite (17 × 19).

There are several things that either are wrong or can be improved in your code.
You can initialize primes with [2, 3] rather than [2], which allows you to start from candidate=3 and to increment it by 2 instead of 1, since 2 is the only even prime number.
i = 0 has no point in your code
prep is only used to test if candidate is prime. As soon as you find that candidate % prime is True, you can break out of your for loop, there is no need to continue to test it if you've already found out a divisor.
The biggest mistake in your code: all primes are not palindromic. Of course you know this, but this is what you've written. Starting from 11, you only add primes to your list that are palindromic (you can test and see that 13 is not in primes for instance). Remove the and candidate_sr == candidate_sr_rev in your if so that you add primes to your list correctly. Since you want the n-th prime, you have two choices:
either you define a second list palindromic_primes to which you add every palindromic prime you've encountered and test its length to be equal to n
or you just keep the number of palindromic primes you've encountered and when this number is equal to n, you can return this palindromic prime number.

Your primality test is wrong as you add to primes only palindromic primes.
def symmetricPrime2(n,candidate=1):
primes = []
counter = 0
while True:
i = 0
prep = 0
candidate = candidate + 1
candidate_sr = str(candidate)
#test if candidate is prime
for prime in primes:
if candidate%prime == 0:
prep += 1
#test if candidate is palindromic
candidate_sr_rev = candidate_sr[len(candidate_sr)::-1]
if prep == 0:
primes.append(candidate)
if candidate_sr == candidate_sr_rev:
counter += 1
if counter == n:
return candidate

Related

Prime checker including non primes

I am trying to solve Project Euler number 7.
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?
First thing that came into my mind was using length of list. This was very ineffective solution as it took over a minute. This is the used code.
def ch7():
primes = []
x = 2
while len(primes) != 10001:
for i in range(2, x):
if x % i == 0:
break
else:
primes.append(x)
x += 1
print(primes[-1])
ch7()
# Output is: 104743.
This works well but I wanted to reach faster solution. Therefore I did a bit of research and found out that in order to know if a number is a prime, we need to test whether it is divisible by any number up to its square root e.g. in order to know if 100 is a prime we dont need to divide it by every number up to 100, but only up to 10.
When I implemented this finding weird thing happened. The algorithm included some non primes. To be exact 66 of them. This is the adjusted code:
import math
primes = []
def ch7():
x = 2
while len(primes) != 10001:
for i in range(2, math.ceil(math.sqrt(x))):
if x % i == 0:
break
else:
primes.append(x)
x += 1
print(primes[-1])
ch7()
# Output is 104009
This solution takes under a second but it includes some non primes. I used math.ceil() in order to get int instead of float but I figured it should not be a problem since it still tests by every int up to square root of x.
Thank you for any suggestions.
Your solution generates a list of primes, but doens't use that list for anything but extracting the last element. We can toss that list, and cut the time of the code in half by treating 2 as a special case, and only testing odd numbers:
def ch7(limit=10001): # assume limit is >= 1
prime = 2
number = 3
count = 1
while count < limit:
for divisor in range(3, int(number ** 0.5) + 1, 2):
if number % divisor == 0:
break
else: # no break
prime = number
count += 1
number += 2
return prime
print(ch7())
But if you're going to collect a list of primes, you can use that list to get even more speed out of the program (about 10% for the test limits in use) by using those primes as divisors instead of odd numbers:
def ch7(limit=10001): # assume limit is >= 1
primes = [2]
number = 3
while len(primes) < limit:
for prime in primes:
if prime * prime > number: # look no further
primes.append(number)
break
if number % prime == 0: # composite
break
else: # may never be needed but prime gaps can be arbitrarily large
primes.append(number)
number += 2
return primes[-1]
print(ch7())
BTW, your second solution, even with the + 1 fix you mention in the comments, comes up with one prime beyond the correct answer. This is due to the way your code (mis)handles the prime 2.

Legendre Conjecture - Counting prime numbers

Given an integer n, the function legendre_n should return the number of prime numbers between n^2 and (n+1)^2.
This is the code I wrote:
def legendre_n(n):
"""Returns the number of primes between n**2 and (n+1)**2"""
count = 0
for i in range(n**2, ((n+1)**2)):
if i%2 != 0:
count += 1
return count
print(legendre_n(12)) = > 5 but I'm getting 12
print(legendre_n(3)) => 2 but I'm getting 4
After testing on python tutor, I found out that the condition I set (i%2 != 0) only filters out odd numbers. However, not all odd numbers are prime numbers. I understand that prime numbers should only be divisible by 1 and the number itself, but I'm stucked at setting the correct condition.
This should do the trick:
def legendre_n(n):
"""Returns the number of primes between n**2 and (n+1)**2"""
count = 0
for num in range(n**2, ((n+1)**2)):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
count = num
return count
you want to check either your num is devidable with any other number between 2 and itself (modulo calculation). If not, it is a prime number.
There is no known "fast" computation to determining if a number is prime. The only known methods involve loops of checks (see some of the other answers). This makes prime factorization a key component in cryptography.
The long story short, is that you must define a function like the ones mentioned above, or you must import one. For example, sympy.isprime() is a highly optimized function that probably runs much faster. Of course, if you are going to import the amazing number theory package, why not just do:
import sympy
def legendre_n(n):
count = 0
for _ in sympy.primerange(n**2,(n+1)**2+1):
count += 1
return count
You only need is make a identifier of prime numbers.
you can try this:
def isprime(n):
for i in range(2,n):
if(n%i)==0:return False
return True
def legendre_n(n):
"""Returns the number of primes between n**2 and (n+1)**2"""
count = 0
for i in range(n**2, ((n+1)**2)):
if isprime(i):
count += 1
return count

listing prime numbers from 3 to 21 in python 3

for x in range (3,21):
if(x%2==0):
print (x,'is a not a prime number')
else:
print (x,'is a prime number')
This is my code but when it prints it says 9 is a prime number and 15 is a prime number.
Which is wrong because they aren't so how do I fix that?
.
def isPrime(N):
i = 2
while i**2 <= N:
if N % i == 0:
return False
i+=1
return True
for i in range(3, 21 + 1):
if isPrime(i):
print(i, 'is prime')
else:
print(i, 'is not a prime number')
First of all, create a function for determining whether or not a given number is prime (this is not a requirement but just a good practice). That function is not that hard: it just starts at i = 2 (starting at 1 makes no sense because every number can be divided by it) and check if N can be divided by it. If that is the case, we have found a divisor of N and thus, it isnt prime. Otherwise, continue with the next number: i += 1. The most tricky part of the loop is the stoping condition: i**2 <= N: we dont have to look further, because if some j > i is a divisor of N, then there is some other k < i that is also a divisor of N: k * j == N. If such k exists, we will find it before getting to the point where i * i == N. Thats all. After that, just iterate over each number you want to check for primality.
Btw, the best way to check for the primality of a set of number is using the Sieve of Eratosthenes
Your code only checks if a number is even. All odd numbers are not prime. So write a for-loop that checks if a odd number is divisible by any of the odd number less than that. Sometying like:
For i in (3 to n): If n mod i == 0, n is not prime.

Finding the largest prime number "within" a number

For this question, I need to find the largest prime number within a larger number. For the purpose of the example, let's say the larger number is "123456789", then some of the numbers I would have to check are 12, 456, 234567, etc.
I wrote some Python code to figure this out, but it is running very slow for the number I am trying to check. The actual number I am working with is about 10000 digits, so there are a lot of numbers I need to look at. Here is my code:
num = "123456789"
def isPrime(n):
# 0 and 1 are not primes
if n < 2:
return False
# 2 is the only even prime number
if n == 2:
return True
# all other even numbers are not primes
if not n & 1:
return False
# range starts with 3 and only needs to go up the squareroot of n
# for all odd numbers
for x in range(3, long(n**0.5)+1, 2):
if n % x == 0:
return False
return True
def largestPrime():
largest = 2
for i in range(0,len(num)):
for j in range(i+1,len(num)):
if isPrime(long(num[i:j])):
if long(num[i:j]) > largest:
largest =long(num[i:j])
print largest
def main():
largestPrime()
main()
I'm pretty sure this code gives the correct answer, but as I said, it's really slow. Can anyone help me figure out how to speed this up?
Thanks for any help!
I'd probably use the strategy of starting with the total number of digits and seeing if that's prime. Then keep decreasing the digits by one while shifting over to the left to see if that's prime. Let me explain with an example:
123456789
First check the 9-digit number: 123456789
Then check the 8-digit numbers: 23456789, 12345678
Then Check the 7-digit numbers: 3456789, 2345678, 1234567
etc.
One problem I see is that for some large numbers you are going to be testing the same number many times. For example for '123456712345671234567', your code will test '1234567' 3 times. I suggest you make a set that contains no duplicates, then run your prime test on each number. I also think that sorting the numbers is a good idea because we can stop after the first prime is found.
Next if you are dealing with large numbers (e.g. 10000 digits), I suggest using a statistical primality test. Below I made a Miller-Rabin primality test using pseudocode from wikipedia.
I have pretty much rewritten your code :P
import random
num = '3456647867843652345683947582397589235623896514759283590867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876867843652345683947582397589235623896514759283590784235876784235876324650'
def probablyPrime(num, k):
"""Using Miller-Rabin primality test"""
if num == 2 or num == 3:
return True
if num < 2:
return False
if not num & 1:
return False
# find s and d such that n−1 = (2**s)*d with d odd
d = (num-1) >> 1
s = 1
while not (d & 1):
d = d >> 1
s += 1
# run k times
for _ in range(k):
a = random.randint(2, num-2)
x = pow(a, d, num) # more efficient than x = a**d % num
if not (x == 1 or x == num-1):
for _ in range(s-1):
x = (x**2) % num
if x == 1:
return False
if x == num-1:
break
if not x == num-1:
return False
return True
def largestPrime(num):
num_list = set([])
for i in range(0,len(num)+1):
for j in range(i+1,len(num)+1):
inum = int(num[i:j])
# Don't append numbers that have already appeared
if inum not in num_list:
num_list.add(inum)
# Convert to list and sort
num_list = list(num_list)
num_list.sort(reverse=True)
for num in num_list:
print('Checking ' + str(num))
if probablyPrime(num,100):
print('\n' + str(num) + ' is probably the largest prime!')
return
largestPrime(num)
Another way to improve speed might be python's multiprocessing package.
Code:
def isprime(n):
if n == 2:
return str(n)+" is the biggest prime"
if n % 2 == 0:
return isprime(n-1) #not prime, check again for next biggest number
max = n**0.5+1
i = 3
while i <= max:
if n % i == 0:
return isprime(n-1) #not prime, check again for next biggest number
i+=2
return str(n)+" is the biggest prime"
print "Testing 7:",isprime(7)
print "Testing 23:",isprime(23)
print "Testing 2245:",isprime(2245)
print "Testing 222457:",isprime(222457)
print "Testing 727245628:",isprime(727245628)
Output:
>>>
Testing 7: 7 is the biggest prime
Testing 23: 23 is the biggest prime
Testing 2245: 2243 is the biggest prime
Testing 222457: 222437 is the biggest prime
Testing 727245628: 727245613 is the biggest prime

Please help, this loop isn't working as expected and I don't know how to use booleans in Python

Am trying to write a piece of python code that calculate and print 1000 prime number from 2
however i only got 1999 as the last element in my result. I know there a lot of questions like this asked before but I wanna know why is my code is not working.
btw: how do i declare a boolean value in python? cant find a clue even googled···sad
mylist=[2]
num=1
count=0
while count<1000:
if num>1:
add=1
for i in mylist:
if num%i==0:
add=0
break
if add==1:
mylist=mylist+[num]
num=num+2
count=count+1
print mylist
Your loop should read while len(mylist) < 1000:, and remove all references to count. Either that, or you should only increment count every time you add a prime to the list.
Also, you don't 'declare' values in Python. You simply assign a value of the desired type to a variable, and poof, you have a variable of that type. In this case, True and False are boolean values and you can assign them to variables.
Here is my version in idiomatic (i.e. written the way an experienced Python programmer might write it) Python:
primes = [2]
candidate = 3
while len(primes) < 1000:
isprime = True
for testprime in primes:
if candidate % testprime == 0:
isprime = False
break
if isprime:
primes.append(candidate)
candidate = candidate + 2
print primes
If you want to write it in even terser and faster Python, do this:
import itertools
primes = [2]
candidate_iter = itertools.count(3, 2)
while len(primes) < 1000:
candidate = candidate_iter.next()
if all(candidate % testprime != 0 for testprime in primes):
primes.append(candidate)
print primes
If you're going to use Python, it's good to learn the Python idioms. I've used several below, including itertools.count, using not to test if something is equal to zero, else clauses on loops, and negative indexing to get the last item of a list.
Also, the Python standard is to use four-space indentation, as below; spaces around operators like =, ==, and %; and spaces after commas.
from itertools import count
mylist = [2]
# This will go up by 2s starting from 3: 3, 5, 7, 9...
for num in count(3, 2):
# For each prime already found
for i in mylist:
# if the prime is a factor of the number
if not num % i:
# don't add it
break
else:
# if none of the primes were factors
# add this number to the list of primes
mylist.append(num)
# if there are 1000 numbers in the list, we're done
if len(mylist) == 1000:
break
# print the 1000th prime
print mylist[-1]
The problem is that you're incrementing the variable count for each number in the set 1,3,5,...,2001. Instead you should increment the count only when add == 1
Here's the same as code for the later generations:
primes = [2] # initial list of primes
candidate = 1 # let's start at 1, could start at 3 as well
primesFound = 1 # We've actually found one already
while primesFound <= 1000: # continue till 1000 primes have been found
# using a counter instead of len(primes)
# maybe faster
if candidate > 1: # 1 is not a prime
isPrime = True
for i in primes: # iterate over all primes already found
if candidate % i == 0: # primes should not be divisable
isPrime = False # not a prime
break # no use going through the rest of the primes
if isPrime: # candidate is a prime so
primes = primes + [candidate] # add it to the primes list
primesFound += 1 # increment the prime counter
candidate += 2 # we can skip all even numbers
print primes # done.

Categories

Resources