Understanding recursive odd/even functions - python

I'm currently studying python from http://www.sololearn.com/Play/Python and I'm having trouble understanding why this code works.
def is_even(x):
if x == 0:
return True
else:
return is_odd(x-1)
def is_odd(x):
return not is_even(x)
print(is_odd(1))
I get how recursion works for a fibonacci and factorial but I can't wrap my head around this one.

is_even's base case resolves to True. Since is_odd(x) returns not is_even(x), the value True will be a part of the expression returned by is_odd. The question is how many times will that True value be negated. By tracing the calls you can see it will be negated an even number of times, and hence "retain" its truthiness, when x is odd [e.g.: x=3 ==> (not (not (not (not True)))) == True] and an odd number of times, and hence "lose" its truthiness, when x is even [e.g.: x=2 ==> (not (not (not True))) == False]. There's probably some term from logic that names this general property of multiple negation.

It's based on an inductive definition of evenness:
Zero is even
If some number "n" is even, then "n+1" is not even
If some number "n" is not even, then "n+1" is even
"odd" is obviously "not even".
The code takes this definition, and checks it backwards - using recursion.
If i have zero, then it is even
If I have some other number "n" , then it is even if "n-1" is not - that is, if "n-1" is odd.

That recursive function is really a bad way to teach recursion, you should apply recursion only when it's useful. In fact, test those functions with negative numbers and you'll get RuntimeError: maximum recursion depth exceeded errors.
To check parity numbers you'd better use % operator or & and operator, ie:
def is_even(x):
return (x & 1) == 0
def is_odd(x):
return (x & 1) == 1
That said, I think #Elazar & #DAXaholic answers should give you some insights about that buggy recursive function and wrap your mind about it.

A little hint:
0 -> True
1 -> not True
2 -> not not True
3 -> not not not True
...
and so on.

Related

Python Modulo Operator without An Equal Sign and A Not-Equal Sign

def even_or_odd(number):
return 'Odd' if number % 2 else 'Even'
print(even_or_odd(2))
Why does this Python code print Even instead of Odd?
The expression number % 2, where number is even, will give you zero. That's a falsey value in Python, hence the if will fail and it will output Even. It's no different to:
>>> if 0:
... print('zero')
... else:
... print('nonzero')
...
nonzero
If you wanted the if statement to succeed for an even number, you would be better off using number % 2 == 0, which will give you True for even numbers. That equivalent statement would be written as:
return 'Even' if number % 2 == 0 else 'Odd'
However, given your constraints in the title (no == or !=), that's not allowed(a). The use of "reversed" logic gets around this problem.
By the way, other methods to do this could include (amongst probably a great many more):
return 'Even' if not number % 2 else 'Odd'
return ['Even', 'Odd'][number % 2]
(a) Though I rather dislike artificial limitations of this type educators often slip into assignments. After all, when will a developer really be called upon to implement something without the = key? Maybe if their keyboard is broken? But then, your bigger issue is surely working for a company that won't shell out $5 for a new keyboard :-)

Is my code correct to find a prime number by means of recursion in python? or is the answer key?

I am studying Python by the book "a beginner guide to python 3" written by Mr.John Hunt. In chapter 8, which is about recursion, there is an exercise, that demands a code in which a prime number is found by recursion. I wrote first code below independently, but the answer key is written in different structure. Because I am very doubtful about recursion, What is your analysis about these two? Which is more recursive?
My code:
def is_prime(n, holder = 1):
if n == 2:
return True
else:
if (n-1 + holder)%(n-1) == 0:
return False
else:
return is_prime(n-1, holder+1)
print('is_prime(9):', is_prime(9))
print('is_prime(31):', is_prime(31))
Answer key:
def is_prime(n, i=2):
# Base cases
if n <= 2:
return True if (n == 2) else False
if n % i == 0:
return False
if i * i > n:
return True
# Check for next divisor
return is_prime(n, i + 1)
print('is_prime(9):', is_prime(9))
print('is_prime(31):', is_prime(31))
My suggestion in this case would be not to use recursion at all. Whilst I understand that you want to use this as a learning example of how to use recursion, it is also important to learn when to use recursion.
Recursion has a maximum allowed depth, because the deeper the recursion, the more items need to be put on the call stack. As such, this is not a good example to use recursion for, because it is easy to reach the maximum in this case. Even the "model" example code suffers from this. The exact maximum recursion depth may be implementation-dependent, but for example, if I try to use it to compute is_prime(1046527) then I get an error:
RecursionError: maximum recursion depth exceeded while calling a Python object
and inserting a print(i) statement shows that it is encountered when i=998.
A simple non-recursive equivalent of the "model" example will not have this problem. (There are more efficient solutions, but this one is trying to stay close to the model solution apart from not using recursion.)
def is_prime(n):
if n == 2:
return True
i = 2
while i * i <= n:
if n % i == 0:
return False
i += 1
return True
(In practice you would probably also want to handle n<2 cases.)
If you want a better example of a problem to practise recursive programming, check out the Tower of Hanoi problem. In this case, you will find that using recursion allows you to make a simpler and cleaner solution than is possible without it, while being unlikely to involve exceeding the maximum recursion depth (you are unlikely to need to consider a tower 1000 disks high, because the solution would require a vast number of moves, 2^1000-1 or about 10^301).
As another good example of where recursion can be usefully employed, try using turtle graphics to draw a Koch snowflake.
I'd say the Answer Key needs improvement. We can make it faster and handle the base cases more cleanly:
def is_prime(n, i=3):
# Base cases
if n < 2:
return False
if n % 2 == 0:
return n == 2
if i * i > n:
return True
if n % i == 0:
return False
# Check for next divisor
return is_prime(n, i + 2)
The original answer key starts at 2 and counts up by 1 -- here we start at 3 and count up by 2.
As far as your answer goes, there's a different flaw to consider. Python's default stack depth is 1,000 frames, and your function fails shortly above input of 1,000. The solution above uses recursion more sparingly and can handle input of up to nearly 4,000,000 before hitting up against Python's default stack limit.
Yes your example seems to work correctly. Note However, that by the nature of the implementation, the answer key is more efficient. To verify that a number n is a prime number, your algorithm uses a maximum of n-1 function calls, while the provided answer stops after reaching the iteration count of sqrt(n). Checking higher numbers makes generally no sense since if n is dividable without remainder by a value a > sqrt(n) it has to also be dividable by b = n % a.
Furthermore, your code raises an exception for evaluating at n = 1 since the modulo of 0 is not defined.

Why does my definition for function read a number as if it is negative?

I have an issue with my code when defining a function. When giving an input number (defined by n), I want my code to define the Fibonacci series of this number. However, even if the number n is positive, the fibo function still reads the number as it is negative and prints 'None'. Why does it do that? Please find my code below:
def fibo(x):
if x > 0:
if x <= 1:
return x
else:
return(fibo(x-1) + fibo(x-2))
elif x < 0:
return None
n = int(input())
for i in range(n):
print(fibo(i))
I think you’re actually seeing something a bit different here. What happens if the argument to your function is 0? In that case, neither branch of the if/elif will execute, since zero is neither greater than nor less than zero. The effect of this is that the function finishes without executing a return statement, which is where the None is coming from.
To fix this, change the first condition in your if statement to read
if x >= 0:
As a note, since Python functions implicitly return None if you don’t explicitly return anything, you don’t actually need the elif here. Do you see why?
Hope this helps!

Python Debugging: weird event when negative sign is in front

I was doing an assignment question.
Write a program, divisible_by_11(num), to return the divisibility of num
by 11. i.e. divisible_by_11(num) should return True is num is divisible by 11,
or False otherwise. Implement this function recursively and using the following algorithm.
Note: a number is divisible by 11 if the difference between the sum of odd digits
and the sum of even digits is divisible by 11. Note that 0 is divisible by 11.
def divisible_by_11(num):
def helper(num,i):
if num==0:
return 0
elif i%2:
return helper(num//10,i+1)-num%10
Question is about replacing the above line with return -num%10+ helper(num//10,i+1)
elif i%2==0:
return num%10+helper(num//10,i+1)
return helper(num,0)%11==0
this code works, however if I wrote return -num%10+ helper(num//10,i+1) instead of return helper(num//10,i+1)-num%10, my code would fail. Can anyone tell me what's happening?
The issue with the alternate form is due to order of operations. The unary-minus operator binds more tightly than the mod operator. That is, the expression -num%10 is interpreted as (-num) % 10, and the modulus of a negative number is not the same thing as its last digit.
There are a few ways you could fix it. The easiest would probably be to add your own parentheses so that the mod happens first: return -(num%10) + helper(num//10,i+1) should work as expected.
Unrelated to that issue, I'm very skeptical that your assignment allows you to do %11 in the final return, since that operation is all you would need to solve the whole problem without the rest!
Instead, I suspect it wants you to use recursion for that part too (and maybe not for adding up the digits). Instead of return helper(num,0)%11==0, try:
while num > 10:
num = helper(num, 0)
return num == 0

Python 3: Recursivley find if number is even

I am writing a program that must find if a number is even or not. It needs to follow this template. I can get it to find if a number is even or not recursively
The key is that you need to return a boolean value:
def isEven(num):
if (num <= 0):
return (num == 0)
return isEven(num-2)
For larger numbers though this quickly exceeds the default maximum recursion depth for Python. That can be remedied by calling sys.setrecursionlimit(n) where n is the number of recursive calls you want to allow. n in turn is limited by the platform you are on.
Try this, it works for integer values with 0 <= n <= sys.getrecursionlimit()-2:
def even(n):
return True if n == 0 else odd(n - 1)
def odd(n):
return False if n == 0 else even(n - 1)
It's a nice example of a pair of mutually recursive functions. Not the most efficient way to find the answer, of course - but nevertheless interesting from an academic point of view.
This template will help. You need to fill in the commented lines. The one you have in the question won't work - you aren't passing anything into isEven. This will only work if n >= 0, otherwise it will crash your program. Easy enough to fix if you ever need to deal with negative numbers.
def isEven(n):
if n == 0:
# Number is even
elif n == 1:
# Number is odd
else:
# Call the function again, but with a different n
Taking up wim's challenge to find a "different" way to do this: The prototypical recursive pattern is foo(cdr(x)), with a base case for the empty list… so let's write it around that:
def isEven(num):
def isEvenLength(l):
if not l:
return True
return not isEvenLength(l[1:])
return isEvenLength(range(num))
A really dumb use case for recursion, but here is my version anyway
import random
def isEven(num):
if random.random() < 0.5:
# let's learn about recursion!
return isEven(num)
else:
# let's be sane!
return num % 2 == 0
disclaimer: if you submitted this you'd probably tick off the teacher and come across as a smartypants.

Categories