0

I'm trying to compute the root of tanh(x) as an exercise.

I'm using the Newton-Raphson method, where the algorithm asks for an initial guess

The algorithm is supposed to not converge for initial guesses larger than about 1. But I get a math range error before it even gets to that.

This is the code I'm using

from math import *
def f(x):#define the function
    return tanh(x)

def fdiv(x):#define its derivative
    return 4*(cosh(x))**2/(cosh(2*x)+1)**2

def Raphson(rx0):
    return (rx0-f(rx0)/fdiv(rx0))#according to the Newton Raphson Method

def Q1_6_Raphson(rx0,Iter=1):
    if Iter > 30:#maximum iterations allowed is 30
        print("Newton Raphson Algorithim did not converge after 30 Trials, try other initial         guesses")
        return
    elif fdiv(rx0)==0:
        print("The initial guess you chose leads to diving by zero in the Newton-Raphson method. Choose another guess")
        return
    print(Iter, 'Newton-Raphson ' +str(rx0) +' error ' +str(rx0-(0)))
    if rx0==0:
        return
    else:
        return Q1_6_Raphson(Raphson(rx0),Iter=Iter+1) # call the function recursively

When I try running Q1_6Raphson(5), for example, I get:

Traceback (most recent call last):
  File "<pyshell#101>", line 1, in <module>
Q1_6_Raphson(5)
  File "C:\Users\AsafHaddad\Documents\סמסטר 8\חישובית\Targil_3\Question1.6.py", line 40, in Q1_6_Raphson
    return Q1_6_Raphson(Raphson(rx0),Iter=Iter+1) # call the function recursively
  File "C:\Users\AsafHaddad\Documents\סמסטר 8\חישובית\Targil_3\Question1.6.py", line 33, in Q1_6_Raphson
    elif fdiv(rx0)==0:
  File "C:\Users\AsafHaddad\Documents\סמסטר 8\חישובית\Targil_3\Question1.6.py", line 21, in fdiv
    return 4*(cosh(x))**2/(cosh(2*x)+1)**2
OverflowError: math range error

From what I read, math range error occurs when the number is just too big. But what I don't understand is that every function called upon in my code is ok with 5 as an input:

>>> f(5)
0.9999092042625951
>>> fdiv(5)
0.00018158323094380672
>>> Raphson(5)
-5501.616437351696

So what's the problem? what triggers the math range error?

6
  • The specific exception starts being thrown at fdiv(711) or over (or for -711 and lower). Commented Apr 16, 2014 at 10:18
  • Your Raphson(5) function returns -5501.61643 for rx0 = 5, which is then fed back into your recursive function, which then passes that new value to fdiv(); -5501 is well lower than -711. Commented Apr 16, 2014 at 10:33
  • Yeah - so that's kind of what I'm asking. if everything for 5 doesn't give a big number, why should the whole algorithm fail with a math range error. Commented Apr 16, 2014 at 10:35
  • 1
    Because the next step in the recursion gives a big (negative) number. Commented Apr 16, 2014 at 10:36
  • ok dude I see what you mean. I just thought it would at least print the line with the value -5501.61643 and then give the error. But I guess the whole function is evaluated before printing a new line. Thanks Commented Apr 16, 2014 at 10:44

2 Answers 2

1

The Raphson(5) call returns a large negative number:

>>> Raphson(5)
-5501.616437351696

This is passed on to the recursive call:

return Q1_6_Raphson(Raphson(rx0),Iter=Iter+1)

so Q1_6_Raphson() is called with -5501.616437351696 as the rx0 argument. This is then passed on to fdiv():

elif fdiv(rx0)==0:

which throws the exception because that number is larger than what math.cosh() can handle:

>>> fdiv(-5501.616437351696)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fdiv
OverflowError: math range error

Any value outside of the range [-710, +710] would throw that exception; within that range you'd get a different exception:

>>> fdiv(-710)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fdiv
OverflowError: (34, 'Result too large')

because you are still exceeding the limits of your platform floating point support.

Only values in the range [-177, +177] give a result.

Sign up to request clarification or add additional context in comments.

Comments

0

Long comment: Could you please elaborate how you got the derivative? The normal approach via the quotient formula for derivatives gives just simply

d/dx tanh(x)=(cosh(x)**2-sinh(x)**2)/cosh(x)**2
            =1-tanh(x)**2         or
            =1/cosh(x)**2

Since

cosh(2x)=cosh(x)**2+sinh(x)**2=2*cosh(x)**2-1, 

your derivative amount to

4*(cosh(x))**2/(cosh(2*x)+1)**2 = 1/cosh(x)**2

so that it gives the correct result, but is a needlessly complicated formula.


Note: The Newton iteration can, in this particular instance, be simplified to

xnext = x - 0.5*sinh(2*x)

The derivative of this is

d(xnext)/dx = 1 - cosh(2*x) = -2*sinh(x)**2

The domain of contractivity is thus defined by cosh(2*x)<2, which is equivalent to

|x|<0.5*ln(2+sqrt(3))=ln(1+sqrt(3))-0.5*ln(2)

2 Comments

Yeah man, you're right. The derivative comes from a lazy copy-paste from wolframalpha. In fact, using the simple representation, the maximum initial value before an Overflow error is now ~355 (instead of 178). Thanks.
Yes, I see it is given as "alternate form". However, what the rationale for this form is, eludes me. cosh(x)>=1 for all real x, so no regularization or tricks are necessary. And the usual alternate form tanh**2-1 is not given...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.