How does this function for Hamming numbers work? - python

I was trying to write a function to generate Hamming numbers and encountered this code on www.w3resource.com.
The code is very easy but I can't seem to understand the order of output values.
def is_hamming_numbers(x):
if x==1:
return True
if x%2==0:
return is_hamming_numbers(x/2)
if x%3==0:
return is_hamming_numbers(x/3)
if x%5==0:
return is_hamming_numbers(x/5)
return False
def hamming_numbers_sequence(x):
if x==1:
return 1
hamming_numbers_sequence(x - 1)
if is_hamming_numbers(x)==True:
print('%s'%x,end=' ')
hamming_numbers_sequence(10)
I expected the output to be:
10 9 8 8 5 4 3 2
The output would be:
2 3 4 5 6 8 9 10
Could anyone please explain why is the order of numbers reversed? I tried to change the order in the code like this:
if is_hamming_numbers(x)==True:
print('%s'%x,end=' ') #this first
hamming_numbers_sequence(x - 1) #then this line
And it would give the output in the order I expected.

def hamming_numbers_sequence(x):
if x==1:
return 1
hamming_numbers_sequence(x - 1) // repeated here
if is_hamming_numbers(x)==True: // means x=2
print('%s'%x,end=' ')
this function hamming_numbers_sequence(x - 1) will repeat it self until reaching x=1 the blocking instruction if x==1: so the second function will enter with the value of x=2 is_hamming_numbers(2)==True:
so you have the out put you're having if you want to change it try it this way
def hamming_numbers_sequence(x):
print('%s'%x,end=' ')
if x==1:
return 1
hamming_numbers_sequence(x - 1)
if is_hamming_numbers(x)==True:
// do what ever you want here

Related

ending condition for recursive function call

I am new to python.
The below recursive code works as expected, so far so good.
What I am wondering about is why after 5 "loops" it stops calling itself recursively.
x=0
def factfunc(n):
global x
x+=1
print("loop #:", x, "-> ", end="")
if n < 0:
print("returning 'None'")
return None
if n < 2:
print("returning '1'")
return 1
print ("n=",n)
return n * factfunc(n - 1)
print ("Finally returned:", factfunc(5))
Output:
loop #: 1 -> n= 5
loop #: 2 -> n= 4
loop #: 3 -> n= 3
loop #: 4 -> n= 2
loop #: 5 -> returning '1'
Finally returned: 120
Hints would be appreciated. Thanks.
Not sure if I am supposed to answer my own question, doing it anyway:
Thanks to trincot's comment I believe I have understood now, I think this is what happens:
return 5 x # not returning anything here, instead calling itself again
(return 4 x # not returning anything here, instead calling itself again
(return 3 x # not returning anything here, instead calling itself again
(return 2 x # not returning anything here, instead calling itself again
(return 1) # returning 1 (no more recursive action from now on)
) # returning 1 x 2 = 2
) # returning 2 x 3 = 6
) # returning 6 x 4 = 24
# 'finally' returning 5 x 24 = 120
=> 120
Hope the above is understandable. Thanks again.

how to read this function

def cat(xx):
if (xx<1):
return 5
if (xx<2):
return 2
if(xx<3):
return 4
if(xx<4):
return 7
if(xx<5):
return 8
if(xx<6):
return 6
if(xx<7):
return 1
if(xx<8):
return 9
if (xx<9):
return 3
else:
return cat(xx-9)
print(cat(38))
the answer python gives me is 4. I am not sure why it gives me this number. I know there are multiple if statements and not elif but I don't know how that causes this answer
The stack call of cat(38) will be:
print(cat(38))
return(cat(38-9))
return(cat(29))
return(cat(20))
return(cat(11))
return(cat(2))
<-- will return 4 since `xx<3` will evaluate to true
The function keeps on substracting 9 to xx until it returns something different from cat(xx-9). When you enter 38 you get 2 by the fourth time you enter the function recursively and then the output is 4
else:
return cat(xx-9)
So because you did print(cat(38)) but there is no if statement when the number is above 9 so it will go to else but what you did was to recall the function instead of returning the number.
Why it gives you 4 every time is because the function is in a loop and it will continue to xx-9 until it finds a valid if statement then it will return the number 4 for example:
38 - 9 = 29, 29 - 9 = 20, 20 - 9 = 11, 11 - 9 = 2 <--- this is what the function is doing.
Solution:
else:
return xx-9

Long multiplication of two numbers given as strings

I am trying to solve a problem of multiplication. I know that Python supports very large numbers and it can be done but what I want to do is
Enter 2 numbers as strings.
Multiply those two numbers in the same manner as we used to do in school.
Basic idea is to convert the code given in the link below to Python code but I am not very good at C++/Java. What I want to do is to understand the code given in the link below and apply it for Python.
https://www.geeksforgeeks.org/multiply-large-numbers-represented-as-strings/
I am stuck at the addition point.
I want to do it it like in the image given below
So I have made a list which stores the values of ith digit of first number to jth digit of second. Please help me to solve the addition part.
def mul(upper_no,lower_no):
upper_len=len(upper_no)
lower_len=len(lower_no)
list_to_add=[] #saves numbers in queue to add in the end
for lower_digit in range(lower_len-1,-1,-1):
q='' #A queue to store step by step multiplication of numbers
carry=0
for upper_digit in range(upper_len-1,-1,-1):
num2=int(lower_no[lower_digit])
num1=int(upper_no[upper_digit])
print(num2,num1)
x=(num2*num1)+carry
if upper_digit==0:
q=str(x)+q
else:
if x>9:
q=str(x%10)+q
carry=x//10
else:
q=str(x%10)+q
carry=0
num=x%10
print(q)
list_to_add.append(int(''.join(q)))
print(list_to_add)
mul('234','567')
I have [1638,1404,1170] as a result for the function call mul('234','567') I am supposed to add these numbers but stuck because these numbers have to be shifted for each list. for example 1638 is supposed to be added as 16380 + 1404 with 6 aligning with 4, 3 with 0 and 8 with 4 and so on. Like:
1638
1404x
1170xx
--------
132678
--------
I think this might help. I've added a place variable to keep track of what power of 10 each intermediate value should be multiplied by, and used the itertools.accumulate function to produce the intermediate accumulated sums that doing so produces (and you want to show).
Note I have also reformatted your code so it closely follows PEP 8 - Style Guide for Python Code in an effort to make it more readable.
from itertools import accumulate
import operator
def mul(upper_no, lower_no):
upper_len = len(upper_no)
lower_len = len(lower_no)
list_to_add = [] # Saves numbers in queue to add in the end
place = 0
for lower_digit in range(lower_len-1, -1, -1):
q = '' # A queue to store step by step multiplication of numbers
carry = 0
for upper_digit in range(upper_len-1, -1, -1):
num2 = int(lower_no[lower_digit])
num1 = int(upper_no[upper_digit])
print(num2, num1)
x = (num2*num1) + carry
if upper_digit == 0:
q = str(x) + q
else:
if x>9:
q = str(x%10) + q
carry = x//10
else:
q = str(x%10) + q
carry = 0
num = x%10
print(q)
list_to_add.append(int(''.join(q)) * (10**place))
place += 1
print(list_to_add)
print(list(accumulate(list_to_add, operator.add)))
mul('234', '567')
Output:
7 4
7 3
7 2
1638
6 4
6 3
6 2
1404
5 4
5 3
5 2
1170
[1638, 14040, 117000]
[1638, 15678, 132678]

Function calling function in python

def one_good_turn(n):
return n + 1
def deserves_another(n):
return one_good_turn(n) + 2
print(one_good_turn(1))
print(deserves_another(2))
Since I have two function one_good_turn(n) and deserves_another(n) while calling function I had passed parameter 1 and 2:
I expected the output to be:
2
4
but its shows:
2
5
Why is the output not what I had expected?
I believe you assume that one_good_turn(n) in deserves_another(n) will return the value that is previously computed. No. It gets the current input n which is 2, call the function again, do 2+1 which is 3. Then you add 3 + 2 = 5.
Maybe to get your desired output, you should pass 1 to deserves_another:
def one_good_turn(n):
return n + 1
def deserves_another(n):
return one_good_turn(n) + 2
print(one_good_turn(1)) # 2
print(deserves_another(1)) # 4
A better way is to return the value from one_good_turn and pass it to deserves_another. So you don't need to call one_good_turn again inside deserves_another:
def one_good_turn(n):
n = n + 1
print(n) # 2
return n
def deserves_another(n):
return n + 2
n = one_good_turn(1)
print(deserves_another(n)) # 4
one_good_turn(2) returns 2+1=3.
Then the result is passed to deserves_another, which returns 3+2=5.

Need Help On Code, All Results Are Coming Back False, when 2 should be true

So basically, I need to write a code for the luhn algorithm, but i need to have at least 5 functions
I have written a code to do this, yet I am receiving False results where they should be true. For example, I know that the second and the fourth data pieces in the data file are true for this algorithm, yet all of my outputs are false. Can you help me figure out where I've gone wrong?
This is the code:
def CheckLength(numb):
if len(numb)>12 and len(numb)<17:
return True
else:
return False
def CheckType(numb):
if numb[0]=='4':
return 'Visa'
elif numb[0]=='5':
return 'MasterCard'
elif numb[0]=='6':
return 'Discover'
elif numb[0:2]=='37':
return 'American Express'
else:
return 'Invalid Entry'
def Step1(numb):
total1=0
total2=0
length=len(numb)
for i in range(length-2,-1,-2):
double=eval(numb[i])*2
if double>9:
doublex=str(double)
doubleY=int(doublex[0])+int(doublex[1])
total1+=doubleY
else:
total2+=double
total=total1+total2
return total
def Step2(numb):
total=0
length=len(numb)
for i in range(length-1,-2,-2):
total+=i
return total
def Step3(num1,num2):
total=num1+num2
if total%10==0:
return True
else:
return False
def main():
inFile=open('pa7.cards','r')
cardNum=inFile.readline().strip()
while cardNum!='99999':
step1=Step1(cardNum)
step2=Step2(cardNum)
step3=Step3(step1,step2)
print(step1)
print(step2)
print(step3)
cardNum=inFile.readline().strip()
inFile.close()
main()
This is the data file:
4388576018402626
4388576018410707
37271983
5190828258102121
99999
This is the output i am getting when printing all 3 steps
4
63
False
0
63
False
7
15
False
4
63
False
(My comments as an answer, including suggestions and corrections from #DavidZemens' comments)
In terms of bugs, I think you have:
Step 1 has the return statement inside the loop, so the loop only happens once, then it stops.
def Step1(numb):
for i in range(length-2,-1,-2):
return total
^ -- ^ -- move this left, to where 'for' is
Step 2 is adding up the counter, not the credit card digits, and it's stepping through every other digit instead of every digit:
def Step2(numb):
total=0
length=len(numb)
for i in range(length-1,-1,-1):
total += int(numb[i])
return total
In general code comments, this kind of test:
if len(numb)>12 and len(numb)<17:
return True
else:
return False
is a bit redundant. If (truth test) return True else return False can become return (truth test):
return 12 < len(numb) < 17
and later:
total = num1 + num2
if total%10==0:
return True
else:
return False
can be:
return (num1 + num2) % 10 == 0
This calculation:
double=eval(numb[i])*2
if double>9:
doublex=str(double)
doubleY=int(doublex[0])+int(doublex[1])
total1 += doubleY
is a bit awkward turning the number into text, taking text characters, turning them back into numbers, then adding them up.
What it does is take the number of tens (integer divide by 10) and the remainder (modulo 10), so you could keep it all as numbers with:
double = int(numb[i]) * 2
if double > 9:
total1 += (double // 10) + (double % 10)
eval() is a bad practice, it gives any input complete access to the Python interpreter with no safeguards. In your code, you could use int() instead
Your file loop could be clearer:
def main():
with open('pa7.cards') as inFile:
for cardNum in inFile:
cardNum = cardNum.strip()
step1=Step1(cardNum)
step2=Step2(cardNum)
step3=Step3(step1,step2)
print(step1)
print(step2)
print(step3)
And you might get some benefit by converting the cardNum into a list of numbers once and then working with that, instead of calling int() all over the place.
You can also optimize the two unused functions (assuming you use them elsewhere in the code):
def CheckLength(numb):
return 12 < len(numb) < 17
def CheckType(numb):
"""
returns the type of credit card, based on the first digit or 2 digits
numb; passed as string
"""
n = numb[0] if not numb[0] == '3' else numb[:1]
d = {4:'Visa',
5:'Mastercard',
6:'Discover',
37:'American Express'}
return d.get(int(n), 'Invalid Entry')

Categories