質問

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?

役に立ちましたか?

解決

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.

他のヒント

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)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top