Per stampare: Clicca qui oppure seleziona File » Stampa nel menù del tuo browser.
-----------------------------------------------------------------------------------------------
Questo intervento è stato stampato da Guide di Dada.Net
raggiungibile a http://guide.dada.net
-----------------------------------------------------------------------------------------------
By Fortran di Giuseppe Ciaburro
URL: http://guide.dada.net/fortran/interventi/2001/08/61569.shtml
Fortran di Giuseppe Ciaburro guida dal 04-06-2002
Algoritmo di Newton-Raphson per il calcolo degli zeri di una funzione.
Esistono vari metodi per accelerare il processo di convergenza nella ricerca degli zeri. Anche in questo caso, prendiamo subito in considerazione il metodo "migliore" (se non altro quello più utilizzato). Si tratta del metodo di Newton, detto anche di Newton-Raphson, e si basa sull'assunzione che la derivata prima della funzione in esame possa essere calcolata. Questa la ricetta:
Nelle immediate vicinanze del punto di zero, il metodo funziona molto bene (la sua motivazione nasce infatti dallo sviluppo di Taylor, arrestato in questo caso al prim'ordine). Allontanandosi dal punto di zero, la funzione potrebbe avere peculiarità che rendono il metodo assai problematico, come in questo (pessimo) esempio, dove le tangenti indicate in rosso sono solo causa di guai:

Un buon approccio di programmazione ci permette però di sommare la rapidità del metodo di Newton-Raphson con la stabilità del metodo di bisezione: basta ricorrere ad un passo di bisezione quando il metodo di Newton tenderebbe ad uscire dall'intervallo oppure converge troppo lentamente.
Per comprendere meglio come implementare l'algoritmo in oggetto riporto il codice relativo in fortran 90.
program main
integer, parameter :: dp = kind (1d0)
real (kind = dp) :: x, true
integer :: m
interface
function f(x)
integer, parameter :: dp = kind(1d0)
real (kind=dp), intent(in) :: x
end function f
function g(x)
integer, parameter :: dp = kind (1d0)
real (kind=dp), intent(in) :: x
end function g
end interface
m = 6
x = 4.0_dp
call newton(f,g,x,m)
end program main
subroutine newton(f,g,x,m)
interface
function f(x)
integer, parameter :: dp = kind(1d0)
real (kind=dp), intent(in) :: x
end function f
function g(x)
integer, parameter :: dp = kind(1d0)
real (kind =dp), intent(in) :: x
end function g
end interface
integer, parameter :: dp = kind(1d0)
real (kind=dp), intent(in) :: x
integer, intent(in) :: m
print *, "n x f(x)"
fx = f(x)
print *, 0, x, fx
do n = 1,m
x = x - fx/g(x)
fx = f(x)
print "(i2, f20.16, f20.16)", n, x, fx
end do
end subroutine newton
function f(x)
integer, parameter :: dp = kind (1d0)
real (kind = dp) , intent(in) :: x
f = ((x - 2.0_dp)*x + 1.0_dp)*x - 3.0_dp
end function f
function g(x)
integer, parameter :: dp = kind (1d0)
real (kind = dp), intent(in) :: x
g = (3.0_dp*x - 4.0_dp)*x + 1.0_dp
end function g