Palindromic prime number in python - python

So I'm trying to figure out how to find all the palindrome prime numbers between 2 numbers.
So far my code can find the palindrome but when I check for a prime number, it prints out the non-primes as well. And there are numbers which are printed multiple times.
Could you please help.
Thanks.
a = 0
b = 500
a += 1
for i in range(a,b):
if(str(i) == str(i)[::-1]):
if(i>2):
for a in range(2,i):
y = True
if(i%a==0):
y = False
break
if y:
print(i)

Based on your most recent code, you simply need to make sure that you reset y, which serves as your positive indicator of primality, for each number you test. Otherwise, it will stay False when you get to the number 4, the first composite number.
>>> a = 0
>>> b = 500
>>> a += 1
>>> for i in range(a,b):
y = True
if(str(i) == str(i)[::-1]):
if(i>2):
for a in range(2,i):
if(i%a==0):
y = False
break
if y:
print(i)
3
5
7
11
101
131
151
181
191
313
353
373
383
As you can see, all of these are prime. You can check the list of primes wolframalpha provides to be sure that no palindromic primes have been omitted. If you want to include 2, add a special case for that.

Please see my comments below:
a = 0
b = 500
a += 1
y = True
for i in range(a,b):
if(str(i) == str(i)[::-1]):
print (i) # <--- You print every number that is a palindrome
if(i>2):
for a in range(2,i):
if(i%a==0):
y = False # <--- This never gets set back to True
break
if y:
print(i)
i+=i # <--- This is doing nothing useful, because it's a "for" loop

Look at my code below, we don't need to initialize Y as well. A For-Else block works well.
a = 0
b = 500
a += 1
for i in range(a,b):
if(str(i) == str(i)[::-1]):
if(i>1):
for a in range(2,i):
if(i%a==0):
y = False
break
else:
print(i)
To get 2 included in the answer, just be sure to check the if condition as (i>1) as mentioned by #elias

Here is the pretty fast implementation based on "Sieve of Atkin" algorithm. I calculate all primes numbers up to the end and then filter only palindromic ones where number is greater or equal to start.
import math
import sys
def pal_primes(start,end):
return list(filter(lambda x: str(x)==str(x)[::-1] and x>=start, sieveOfAtkin(end)))
def sieveOfAtkin(limit):
P = [1,2,3]
sql = int(math.sqrt(limit))
r = range(1,sql+1)
sieve=[False]*(limit+1)
for x in r:
for y in r:
xx=x*x
yy=y*y
xx3 = 3*xx
n = 4*xx + yy
if n<=limit and (n%12==1 or n%12==5) : sieve[n] = not sieve[n]
n = xx3 + yy
if n<=limit and n%12==7 : sieve[n] = not sieve[n]
n = xx3 - yy
if x>y and n<=limit and n%12==11 : sieve[n] = not sieve[n]
for x in range(5,sql):
if sieve[x]:
xx=x*x
for y in range(xx,limit+1,xx):
sieve[y] = False
for p in range(5,limit):
if sieve[p] : P.append(p)
return P
if __name__=="__main__":
print(pal_primes(int(sys.argv[1]),int(sys.argv[2])))
Based on this thread:
Sieve Of Atkin Implementation in Python

Related

Palindrome number in python (leetcode)

class Solution:
def isPalindrome(self, x: int) -> bool:
# If x is a negative number it is not a palindrome
# If x % 10 = 0, in order for it to be a palindrome the first digit should also be 0
if x < 0 and x%10 == 0):
return False
reversedNum = 0
while x > reversedNum:
reversedNum = reversedNum * 10 + x % 10
x = x // 10
# If x is equal to reversed number then it is a palindrome
# If x has odd number of digits, dicard the middle digit before comparing with x
# Example, if x = 23132, at the end of for loop x = 23 and reversedNum = 231
# So, reversedNum/10 = 23, which is equal to x
return True if (x == reversedNum or x == reversedNum // 10) else False
This is my code which is giving wrong output for 660,
Expected output : False
My output : True
Can someone tell me how to correct this.
reversedNum = 0
Num=x
while x > 0:
reversedNum = reversedNum * 10 + x % 10
x = x // 10
return True if (Num == reversedNum) else False
You don't really need an explicit check for a negative number because the while loop (in the following code) will not be entered and the return value will be an equality test between zero and some negative number - which is obviously False.
So:
def ispalindrome(x):
n = x
r = 0
while n > 0:
r *= 10
r += n % 10
n //= 10
return r == x
if you convert the number to a string is very simple. you only need to check that the string written backwards is the same
def ispalindrome(x):
return str(x) == str(x)[::-1]
ispalindrome(23132)
>>> True

Palindrome tester gives False for 11 but returns True for 121

Here is my code:
def isPalindrome(x):
if x < 0 or (x % 10 == 0 and x != 0):
return False
rev = 0
while x > rev:
rev = (rev*10 + x % 10)
x /= 10
return x == rev or x == rev/10
x = 11
print(isPalindrome(x))
Why does this code not give the desired results for all positive integer inputs?
Your code has two problems.
The first is that x /= 10 performs a floating point divide, so 11 /= 10 is 1.1, not 1. Integer divide in Python is //.
The second is that you don't want to keep looping while x > rev but rather while x > 0 because you want to reverse every digit of your number. When x > 0, you still have digits in x that you haven't added to the reversed value. The accumulated portion of the reversed value being greater than the part of the answer still to be processed doesn't mean anything.
So here's a working version of your code, at least for your two test cases and a few more I did. I didn't do an exhaustive test.
def isPalindrome(x):
if x < 0 or (x % 10 == 0 and x != 0):
return False
rev = 0
y = x
while y > 0:
rev = (rev*10 + y % 10)
y //= 10
return x == rev or x == rev/10

Project Euler #37 issue

I tried to solve Project Euler #37:
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
I wrote my code in Python but I am facing weird issues.
Here's my code:
def isPrime(n):
if n == 2 or n == 3 or n == 5: return True
if n < 2 or n%2 == 0: return False
if n < 9: return True
if n%3 == 0: return False
if n%5 == 0: return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0: return False
if n%(f+2) == 0: return False
f +=6
return True
def gen(nb):
results = []
nb_str = str(nb)
for k in range(0, len(nb_str) - 1):
results.append(nb_str[k:])
results.append(nb_str[-k:])
return results
def check(nb):
for t in gen(nb):
if not isPrime(int(t)):
return False
return True
c = 0
s = 0
i = 2
while c != 11:
if check(i):
c += 1
s += i
i += 1
print(s)
Where does the error come from? (The expected result is 748317)
I suspect the errors coming from the results list
Yes, the gen() function is not working correctly as your slicing is off, also, you count 2, 3, 5 and 7 as truncatable primes which the question denies.
The second slice should be the other way around:
>>> s = 'abcd'
>>> for i in range(1,len(s)-1):
... print(s[i:])
... print(s[:-i])
...
bcd
abc
cd
ab
which we can see produces the right strings.
Altogether then, the function should be:
def gen(nb):
results = [nb]
nb_str = str(nb)
for k in range(1, len(nb_str)):
results.append(int(nb_str[k:]))
results.append(int(nb_str[:-k]))
return results
note I also added a string to int conversion - not sure how Python didn't make that obvious for you :/
And before get the full solution, Project Euler nearly always gives you an example which you can use to check your code:
>>> check(3797)
True
You must also add a condition in the check function to return False if the number is 2, 3, 5 or 7 as this is stated clearly in the question.
And the result is the expected: 748317.
Joe Iddon has explained the error in your code, but you can speed it up a little by turning gen into an actual generator. That way, you can stop checking the results for a given nb as soon as you detect a composite number (and gen will stop generating them). I've also made a few minor tweaks to your primality tester. Remember, the or operator short-circuits, so if a is True-ish in a or b then it doesn't bother evaluating b.
def isPrime(n):
if n in {2, 3, 5, 7}:
return True
if n < 2 or n%2 == 0:
return False
if n%3 == 0 or n%5 == 0:
return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0 or n%(f+2) == 0:
return False
f += 6
return True
def gen(nb):
yield nb
nb_str = str(nb)
for k in range(1, len(nb_str)):
yield int(nb_str[k:])
yield int(nb_str[:-k])
def check(nb):
for t in gen(nb):
if not isPrime(t):
return False
return True
c = s = 0
# Don't check single digit primes
i = 11
while c < 11:
if check(i):
c += 1
s += i
print(i)
i += 2
print('sum', s)
output
23
37
53
73
313
317
373
797
3137
3797
739397
sum 748317
In fact, you can get rid of the check function, and replace it with all, which also short-circuits, like or does. So you can replace the
if check(i):
with
if all(map(isPrime, gen(i))):

Why doesn't this code work (Leetcode in Python)?

class Solution:
def isHappy(self, n):
list_n, l, ls, num = [n,], 0, 0, 0
while num != 1:
if l != ls:
return False
num = sum([int(i)**2 for i in list(str(n))])
list_n.append(num)
l, ls = len(list_n), len(set(list_n))
return True
Input: 7
Output: False
Expected: True
It's from Happy Number | LeetCode OJ
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
To answer the question: Your code fails because you're confusing num and n. In particular, you compute num always from n, and neither ever changes. Just get rid of one of them, that will also be less confusing. You really should learn to debug, btw... printing num or n inside the loop would have made it clear what's happening.
Using a set would btw be easier and faster, try that as well. Here's one way:
def isHappy(n):
stop = {1}
while n not in stop:
stop.add(n)
n = sum(int(d)**2 for d in str(n))
return n == 1
And here's one that only uses two single ints. Can you see how it works?
def isHappy(n):
s = lambda n: sum(int(d)**2 for d in str(n))
m = s(n)
while m != n:
n, m = s(n), s(s(m))
return n == 1
The reason is as below:
n has to be reset to newest result after each sum operation. So just add this line before return True :
n=num
And for your reference, here is the working code:
def isHappy(n):
list_n, l, ls, num = [n,], 0, 0, 0
while num != 1:
if l != ls:
return False
num = sum([int(i)**2 for i in list(str(n))])
list_n.append(num)
l, ls = len(list_n), len(set(list_n))
n=num # reset n after each sum calculation
return True
You can keep looping while sm which is the sum of the squares of the digits of the current n or until sm is repeated. Returning sm == 1 to test if the number is happy:
def isHappy( n):
# set initial sum of squares
sm = sum(int(i) * int(i) for i in str(n))
seen = set()
# while we have not hit 1 or we get a repeated `sm`
while sm != 1 and sm not in seen:
# add sm to our set
seen.add(sm)
# update sm
sm = sum(int(i) * int(i) for i in str(sm))
# we will get here either when sm is 1 or we had a repeated sm
return sm == 1
Output:
In [2]: for x in range(100+1):
...: if isHappy(x):
...: print(x)
...:
1
7
10
13
19
23
28
31
32
44
49
68
70
79
82
86
91
94
97
100
As per the wiki page description in your question If n is not happy, then its sequence does not go to 1. Instead, it ends in the cycle so if we see repeated values we know the number is not happy. I don't see anywhere in your code that you are checking that condition.

Loop ends with no reason

I am trying to solve problem 4 in project Euler which is:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
The initial code that I wrote is:
def check_reversed(number):
number = str(number)
if number == number[::-1]:
return True
for x in range(100,1000):
for y in range(100,1000):
if check_reversed(x*y) == True:
print x,y,x*y
For some reason the second loop stops at number 583 and outputs the wrong answer. When I change the range though of the second "for" loop to (584,1000), it outputs the correct answer.
My question is why does the second loop ends at number 583?
EDIT : SOLVED: (Thank you for your help!)
def check_reversed(number):
number = str(number)
return number == number[::-1]
max_pal = 0
for x in range(100,1000):
for y in range(100,1000):
if check_reversed(x*y) == True:
if x*y > max_pal:
max_pal = x*y
print max_pal
Your second loop doesn't end at 583 at all; 583 just happens to be the highest y for x = 995 that is a palindrome.
Two lines earlier, your code prints:
993 913 906609
which clearly contradict your analysis.
You need to track the maximum result and not assume that the maximum x gives you the answer.
Note that there is little point in testing the same numbers for y each loop; no need to test the product of range(100, 1000) when combinations will do:
from itertools import combinations
def check_reversed(x, y):
number = str(x * y)
return number == number[::-1]
x, y = max((c for c in combinations(range(100, 1000), r=2) if check_reversed(*c)),
key=lambda c: c[0] * c[1])
print x, y, x * y
your loops just work fine because the last two numbers in your conditions are 995 583
however this script solves your problem
def check_reversed(number):
number = str(number)
if number == number[::-1]:
return True
temp = 0
for x in range(100,1000):
for y in range(100,1000):
if check_reversed(x*y) and temp <= x*y:
temp = x * y
print x,y,x*y

Categories