Loop ends with no reason - python

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

Related

The incrementing here continues to return a 0 value

I was writing the solution to this codewars problem however I've ran into a bit of an issue.
Problem statement:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit, e.g.:
persistence(39) # returns 3, because 39=27, 27=14, 1*4=4 and 4 has only one digit
def persistence(n, t=1, x=0):
if len(str(n)) > 1:
number = [int(i) for i in str(n)]
for i in number:
t = t * i
if len(str(t)) > 1:
x += 1
return(persistence(t,x))
else:
return(x)
else:
return 0
I can't quite figure out what the error is in this code. My hunch is that it's either a parameter error or the way the return() value is placed.
In essence, the code for distilling an integer to it's multiples is correct, so I just added an extra parameter to persistence; setting x = 0 and making it so that each time the if condition was fulfilled it would increment that exact x value. Once the number was distilled, simply output x. Yet it continues to simply output 0 as the final answer. What's the problem here?
Edit: Solution was in the comments, didn't realise how the parameters were passing. Correct version is:
return(persistence(t,1,x))
Also had to set x = 1 for the logic to work on codewars.
There are 2 flaws in Your code:
return(persistence(t,x))
should be
return(persistence(t,1,x))
otherwise the value of x will be assigned to t and x will be defaulted to 0.
Then you must increment x directly after the first test, otherwise You will miss one iteration.
Another way to calculate this is not to switch over to strings, but to do it numerically:
def persistence(n):
iterations = 0; # no iterations yet
while n > 9: # while n has more than 1 digit:
product = 1 # neutrum for result product
while n > 0: # while there a digit to process:
digit = n % 10 # retrieve the right most digit
product *= digit # do the multiplication
n = n // 10 # cut off the processed digit
iterations += 1 # increment iterations
n = product # let n be the newly calculated product
return iterations # return the result
I think you your function's parameters work not as you expect them to do.
When you call function persistence(t, x), the first argument n should become t, and second argument x, should become new x. But in your function, x becomes new t because of their position.
It is quite useful to have bunch of print statements to reveal the bug.
def persistence(n, x=1, t=1):
print('x:', x)
if len(str(n)) > 1:
number = [int(i) for i in str(n)]
for i in number:
t = t * i
print('t:', t)
if len(str(t)) > 1:
x += 1
print('x has changed:', x)
return persistence(t, x)
else:
return x
else:
return 0
print(persistence(39))
print('---------------')
print(persistence(999))
print('---------------')
print(persistence(4))
Passes all test cases with two changes:
You were not updating your n with the new t everytime
Your x was being set to 0 every time. That should be set to 1 in the beginning (default value)
def persistence(n, t=1, x=1):
if len(str(n)) > 1:
number = [int(i) for i in str(n)]
for i in number:
t = t * i
if len(str(t)) > 1:
x += 1
return (persistence(n=t, x=x))
else:
return (x)
else:
return 0
Actually, you can write it without needing both parameters t and n. Just one n is fine as shown below:
def persistence(n, x=1):
if len(str(n)) > 1:
number = [int(i) for i in str(n)]
t = 1
for i in number:
t = t * i
if len(str(t)) > 1:
return x + (persistence(n=t, x=x))
else:
return (x)
else:
return 0

To find the largest palindrome made from the product of two 2-digit numbers

def largest_palindrome(n1,n2):
mylist = [x for x in range(n1,n2)]
for y in mylist:
if y == y[::-1]:
print(y)
else:
pass
largest_palindrome(100,9801)
When I am executing this code the error that comes up is TypeError: 'int' object is not subscriptable.
I need to know what is the problem is in this code and what changes will be done to make this code running.
You need to cast to string to be able to reverse and compare:
def largest_palindrome(): # <-- arguments are not needed
for y in (x for x in range(9801, 100, -1)): # use a generator, that iterates from largest to smallest.
if str(y) == str(y)[::-1]:
return y # early exit when largest match is found (it will be the first)
print(largest_palindrome())
spoiler alert:
9779
as a one liner:
max([x for x in range(9801, 100, -1) if str(x) == str(x)[::-1]])
As a one liner generator
(thanks #Austin in the comments):
next(x for x in range(9801, 100, -1) if str(x) == str(x)[::-1])
Reblochon's answer doesn't solve the problem as it only iterates between the smallest and the biggest number that could come from two two-digit numbers. It doesn,t iterate through two-digit numbers.
def largest_palindrome():
lastBiggestProduct = 0;
lastBiggestNumb = 10;
for firstNum in range(10,100):
a = list(range(lastBiggestNumb,firstNum))
a.extend(range(firstNum+1,100))
for secondNum in a:
prod = firstNum*secondNum
if(prod>lastBiggestProduct and str(prod) == str(prod)[::-1]):
lastBiggestProduct = firstNum*secondNum
lastBiggestNumb = secondNum
return lastBiggestProduct
print(largest_palindrome())
That returns:
9009

Python nested loops - no output

I've just started learning python. I am trying to check if the integer x is palindrome then divide it by a number between range (starting from largest y i.e. 999 ) y=999,998,...,100. If x/y=z and z is also a 3 digit integer then finish. Otherwise subtract 1 from x and do the same procedure.
def EuQ4():
x=998001
p=999
while 10000 < x:
x=x-1
if str(x)== str(x)[::-1]:
while p>100:
if x%p==0:
Pal=x/p
if Pal < 999:
print (Pal,p)
break
else:
x=x-1
else:
p=p-1
else:
x=x-1
EuQ4()
This is question 4 from Project Euler i.e. Find the largest palindrome made from the product of two 3-digit numbers.
You have a few logic errors in here. Some cause loops that just never end. For example, what happens when x % p == 0 but Pal is larger 999? You would get an infinite loop.
I made a few modifications, but it could still use some work.
def EuQ4():
x = 998001
while 10000 < x:
if str(x) == str(x)[::-1]:
print("{} is a pali!".format(x))
# Move it here so each time it stats at the right
# number or else it will just skip it after it does it once.
p = 999
while p > 100:
if x % p == 0:
pali = int(x / p)
if pali < 999:
print(pali, p)
return
p -= 1
x -= 1
EuQ4()
Edit:
I found these mistakes by using the debugger in my IDE. You could have easily done the same thing by going through the code line by line a few times.
I am sorry but it was hurting my head to read your question. If you are trying to learn Python while attempting these questions then I would propose this alternate answer - it does not answer your question but it does lead to the solution and I think it is more Pythonic. The question asks to find the largest palindrone made from the product of two 3 digit numbers. So the inputs should be 3 digit numbers. This code will allow you to specify the number of digits, max and min (as integers).
I am not proposing that this be the best solution the the Euler Problem posed rather it is a solution that gives you exposure to a range of features in Python.
def min_value(integer):
min_val = '1'
for n in range(0,integer-1):
min_val+='0'
return int(min_val)
def max_value(integer):
max_val = '9'
for n in range(0,integer-1):
max_val += '9'
return int(max_val) +1
def find_max_palindrones(x,y):
minimum_value = min_value(x)
maximum_value = max_value(y)
palindrones = []
working_range = [number for number in range(minimum_value,maximum_value,1)]
for x_value in working_range:
for y_value in working_range:
product = x_value * y_value
orig_order = [item for item in str(product)]
rev_order = [item for item in str(product)[::-1]]
if orig_order == rev_order:
palindrones.append(product)
max_p = max(palindrones)
return max_p
>>>find_max_palindrones(3,3)
906609
Put p=999 befor while p > 100 or use for p in range(999, 100, -1).
p = 999
while p > 100
And I think you call x=x-1 too many times.

Palindromic prime number in 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

While loop example

x = y // 2 # For some y > 1
while x > 1:
if y % x == 0: # Remainder
print(y, 'has factor', x)
break # Skip else
x -= 1
else: # Normal exit
print(y, 'is prime')
This is an example for understanding while loop in a book I'm reading, I don't quite understand why a floor division and then y % x? Can someone please explain this piece of code, whats it doing?
Thanks!
This is a lame primality test.
% is the mod operator. It performs division and returns the remainder rather than the result of the division. For example, 5 // 2 == 2, and 5 % 2 == 1.
Commented:
x = y // 2 # For some y > 1 ##Reduce search space to half of y
while x > 1:
if y % x == 0: # Remainder ##If x divides y cleanly (4 / 2 == 2)
print(y, 'has factor', x) ##y is not prime
break # Skip else ##Exit the loop
x -= 1 # Normal exit ##Try the next value
else:
print(y, 'is prime')
The program prints at least one factor of an integer y, or if it has no factors (other than itself and 1), prints that y is prime.
It uses the variable x to try all possible factors greater than one. It starts at the floor of y divided by 2, because no number larger than half of y could be a factor. Using normal division rather than floor division could give you a fractional value if y is odd. (An even better solution is to start with the square root of y - if y is not prime, one of its factors will be less than or equal to its square root.)
Inside the loop, it tests y % x, which is the remainder after dividing y by x. If the remainder is zero, that means that x is a factor of y, and it prints it.
The else clause is executed at the end of the loop, unless a factor is found, in which case the "break" skips out of the loop and the else clause. So either a factor is found, or it's prime.
Here's the improved code with the indentation fixed:
import math
def check_primality(y):
x = int(math.sqrt(y))
while x > 1:
if y % x == 0:
print y, 'has factor', x
break
x -= 1
else:
print y, 'is prime'
The code simply checks if the square root of x has been reached. Note that you can check the primality of a number by checking if the integers from 2 up to the square root of x divides x perfectly (without a remainder).
the logic is:
if y modulo x is 0, it means that x is a dividor of y, so y has a factor. print that, and break out of the loop.
if not, decrease x by 1, and try again.
but some things are broken in this code:
the else statement position
the fact the 'print y is prime' is after the loop - it will always print it.
For any number (x) which is not prime, there would be a factor greater than 1 and less than (x/2).
9 = 3*3
The logic is to iterate through all the numbers <= x/2 and check if the number divides.
I think the program tries to find the biggest prime factors of y.
If y is a prime factor it prints this as well.
x = y // 2 is for testing the numbers in the range x: 2..y/2.
A better approach would be to test only the numbers x: 2..sqrt(y)
the % denotes a modulus which gives you the remainder of division...
and this code checks for prime Y and also checks if Y is a multiplier of x...
x = y // 2 #x=the division or modulus of y , 2
while x > 1: #you want to check if this is a division result or a modulus
if y % x == 0: # if y is a multiplier of x
print(y, 'has factor', x)
break # break the while loop
x -= 1 # decreament x
else: # this line executes if the wihle reached x > 1 and didnt break
print(y, 'is prime')
so if y is a multiplier of x it will decreament x and the loop continue
otherwise it will print y is prime

Categories