0
from sympy import *

x = Symbol('x')

f = (2*x) + 1

fprime = f.diff()

f = lambdify(x, f)
fprime = lambdify(x, fprime)
newtons_expr = lambdify(x, x - (f(x) / fprime(x)) )


def newtons_method(guess):

    approx = newtons_expr(guess)

    if Abs(approx - guess) < 0.001:
        print(approx) # <-- returns a float (-0.5)
        print(type(approx)) # <-- returns "<class 'float'>"
        return approx # <-- returns a None
    else:
        newtons_method(approx)

print(newtons_method(1))

I built this function using SymPy to evaluate one of the solutions to an equation using Newton's method. For some reason, however, its returning a None instead of a float, even though it explicitly prints a float before it returns the value of approx. What's wrong here? I've never seen this before.

  • 1
    The function doesn't return on both branches. It should also return in the else clause. i.e. `return newtons_method(approx)` – Paul Rooney Apr 08 '18 at 22:31
  • @PaulRooney the else clause is used to call the function recursively. with newton's method, the approximation one gets from plugging in the first guess becomes the second guess and so on until conditions are met. –  Apr 08 '18 at 22:36
  • Ultimately the function has to always return something. As you have it now, unless the number is close enough on the first iteration the function returns None. If simply returning in the else clause is not the right thing to do need to rethink how your function is structured. – Paul Rooney Apr 08 '18 at 22:41
  • @PaulRooney That can't be the case. The function is running multiple iterations to reach the value of -0.5 and its printing it before `return`. The function actually prints my answer, but it just doesn't return it correctly for some reason. Also, if you stick `print` statements in the function to measure its progress, it actually nears the value -0.5 w/ each iteration. –  Apr 08 '18 at 22:49
  • Don't get me wrong the recursion are still executing, but they aren't returning anything. You need to carry the final value back down the call stack by returning in every call. The value from the base case doesn't just pop out at the end by magic. – Paul Rooney Apr 08 '18 at 22:56
  • @PaulRooney Yep, I understand what you meant now. These recursive functions are confusing; I needed to return the value of the function's reference to itself? I tried that and it fixed my problem. Thanks! –  Apr 08 '18 at 23:47
  • You aren't returning a reference to the function. You are returning the value returned from the function. You are just forwarding the value on from the last recursive call (base case) to the caller who make the initial call. I know its a biit confusing, but its worth reading up on the subject to get it straight in your mind. – Paul Rooney Apr 09 '18 at 01:00
  • @GianfrancoRomaelle if you want to generate code for newtons method you might be interested in this branch: https://github.com/sympy/sympy/pull/13100/files#diff-3a6d66b018fe657a69245850eb8f2a1aR11 – Bjoern Dahlgren Apr 09 '18 at 11:54

1 Answers1

0

Thanks @PaulRooney!

My mistake was was here:

else:
    newtons_method(approx)

When you're calling a recursive function, you need to have it return itself every call; otherwise, it will return None. It should've been:

else:
    return newtons_method(approx)

I found this video explaining the "call stack" Paul mentions in our discussion. I watched it and it gave me some insight as to what my function was doing logically: https://www.youtube.com/watch?v=k0bb7UYy0pY