Reputation: 2207
My task is this:
What is the only (double-digit, or above) Prime number that is palindromic in both base-2 (binary), and base-10 (decimal) instances?
Whenever I run this code nothing happens, and it acts like an infinite loop. What am I doing wrong, or how can I improve? Many thanks in advance.
def isPrime(n):
if type(n) != int or n <= 1:
return False
elif n == 2:
return True
elif n%2 == 0:
return False
else:
for x in range(2, int(n**0.5)+1):
if n%x == 0:
return False
break
return True
def isPalindrome(x):
num = str(x)[::-1]
if str(x) == num:
return True
else:
return False
while True:
a = 11
if isPrime(a) and isPalindrome(a) == True:
if isPalindrome(bin(a)) == True:
print a
break
else:
a+=2
print a
--------- Edit: **SOLVED** ---------
Revised code:
def isPrime(n):
if n < 2 or n%2 == 0:
return False
if n == 2:
return True
else:
for x in range(3, int(n**0.5)+1, 2):
if n%x == 0:
return False
return True
def isPalindrome(x):
num = str(x)[::-1]
return str(x) == num
a = 11
while True:
if isPrime(a) and isPalindrome(a) and isPalindrome(format(a, "b")):
print a
break
a+=2
Thank you to all who contributed answers.
Upvotes: 1
Views: 623
Reputation: 1123400
The output of bin()
is never a palindrome, because the characters 0b
are prepended to it:
>>> bin(3)
'0b11'
>>> isPalindrome(bin(3))
False
Either slice those two characters of, or use format()
to produce a binary representation:
>>> format(3, 'b')
'11'
>>> isPalindrome(format(3, 'b'))
True
Your loop has another problem: it won't increment if you found a palindromic prime that is not a palindromic prime in base 2:
if isPrime(a) and isPalindrome(a) == True:
if isPalindrome(format(a, 'b')) == True:
print a
break
# no else here
else:
a+=2
print a
Just test for all conditions in one test:
if isPrime(a) and isPalindrome(a) and isPalindrome(format(a, 'b')):
print a
break
a += 2
There is rarely a need to test for == True
in a boolean test.
Next is that you reset a
in the loop:
while True:
a = 11
It doesn't matter what you do to a
in the rest of the loop, at the top it goes back to 11. Move that out of the loop:
a = 11
while True:
if isPrime(a) and isPalindrome(a) and isPalindrome(format(a, 'b')):
print a
break
a += 2
Whenever you write if comparison: return True
followed by else: return False
, just return the test instead:
def isPalindrome(x):
num = str(x)[::-1]
return str(x) == num
because the ==
comparison operator already returns a boolean value.
Your primality test doesn't need to test for the type of n
, really (you only ever pass in integers), but the correct way to test for a type is to use:
isinstance(n, int)
as this allows for subclasses of int
too. Even if you do need to limit something to a very specific type and cannot allow for subclasses, you'd use:
type(n) is int
as types are singletons.
Taking advice from isPrime Function for Python Language your isPrime()
function would be a little faster if you used:
def isPrime2(n):
if n < 2: return False
if n == 2: return True
for i in range(3, int(n ** 0.5) + 1, 2): # only odd numbers
if n % i == 0:
return False
return True
instead.
Your loop could be made more efficient by limiting the number of values you look at. If you look at the Palindronic Prime series on the OEIS you'll see that apart from 11, all base-10 palindromic primes have an odd number of digits, so you can skip large swathes of numbers. The following would produce better candidates:
def palindromic_candidates():
yield 11
outer = 1
while True:
for i in range(10):
yield int('{}{}{}'.format(outer, i, str(outer)[::-1]))
outer += 1
Demo:
>>> from itertools import islice
>>> pc = palindromic_candidates()
>>> list(islice(pc, 30))
[11, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383]
>>> list(islice(pc, 100, 130))
[13931, 14041, 14141, 14241, 14341, 14441, 14541, 14641, 14741, 14841, 14941, 15051, 15151, 15251, 15351, 15451, 15551, 15651, 15751, 15851, 15951, 16061, 16161, 16261, 16361, 16461, 16561, 16661, 16761, 16861]
Use this instead of your while True
loop, remove the a += 2
line:
for a in palindromic_candidates():
if isPrime(a) and isPalindrome(format(a, 'b')):
print a
break
where you can drop the test for base-10 palindromes as the generator produces only palindromes.
Upvotes: 7