将函数作为参数传递给子例程时出现分段错误
我尝试说明如何将函数传递给Newton Raphson过程。我用一个非常简单的函数(称为unefonction
见下文)成功,但它不适用于具有参数的函数。这第二个功能称为gaussienne
,它有一个参数x和两个可选参数mu
和sig
。在我的牛顿raphson程序中,我以这种方式称作功能:f(x)
。对我来说奇怪的是,在执行过程中,程序的作用好像有可选参数sig
和mu
,但它们不会...因此我不明白...将函数作为参数传递给子例程时出现分段错误
这里是包含模块功能
module fonction
implicit none
! parametre pour la gaussienne
double precision :: f_sigma = 1.d0, f_mu = 0.d0
! pi accessible uniquement en interne
double precision, parameter :: pi = 3.14159265359d0
contains
double precision function unefonction(x)
! fonction : unefonction
! renvoie
! $\frac{e^x - 10}{x + 2}$
implicit none
! arguments
double precision, intent(in) :: x
unefonction = (exp(x) - 10.)/(x + 2.)
end function unefonction
! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
double precision function gaussienne(x, mu, sig)
! fonction gaussienne
! utilise les parametres definis dans le module si
! mu et sig ne sont pas passes en argument
implicit none
! arguments
double precision, intent(in) :: x
double precision, intent(in), optional :: mu, sig
! variables locales
double precision :: norme, moy, sigma
! sigma
if (present(sig)) then
write(*,*)"sig present"
sigma = sig
else
sigma = f_sigma
end if
! mu
if (present(mu)) then
write(*,*)"mu present"
moy = mu
else
moy = f_mu
end if
! calcul de la gaussienne
norme = 1.d0/(sigma * sqrt(2.d0 * pi))
gaussienne = norme * exp(-(x - moy)**2/(2.d0 * sigma**2))
end function gaussienne
end module fonction
这里是包含牛顿拉夫逊过程
module rechercheRacine
implicit none
contains
subroutine newtonRaphson(racine, f, eps, cible)
! recherche l'antecedant de cible
implicit none
! arguments
double precision, intent(inout) :: racine
double precision, intent(in), optional :: cible, eps
! fonction dont on cherche la racine
double precision, external :: f
! variables locales
integer :: compteur
double precision :: xold, xnew, delta, valcible
double precision :: threshold, fprim, fdex
! precision
if (present(eps)) then
threshold = eps
else
threshold = 1.d-10
end if
! valeur cible
if (present(cible)) then
valcible = cible
else
valcible = 0.d0
end if
write(*,*) "--------------------------------------------------------"
write(*,*) " NEWTON RAPHSON"
write(*,*) "--------------------------------------------------------"
write(*,"('x0 = ',e16.6)") racine
write(*,"('seuil = ',e16.6)") threshold
write(*,"('cible = ',e16.6)") valcible
write(*,*) "--------------------------------------------------------"
write(*,*) " ITERATIONS"
write(*,*) "--------------------------------------------------------"
! initialisation
compteur = 0
delta = 1.d0
xold = racine
write(*, '(i4,4e16.6)') compteur, f(xold), xold, 0., threshold
! iterations
do while (delta > threshold .and. compteur <= 100)
! calcul de la fonction en xold
fdex = f(xold) - valcible
! calcul de la derivee numerique
fprim = (f(xold + threshold) - f(xold - threshold))/(2.d0 * threshold)
! application de l'iteration de Newton Raphson
xnew = xold - fdex/fprim
delta = abs(xnew - xold)
compteur = compteur + 1
! affichage de la convergence
write(*, '(i4,4e16.6)') compteur, fdex, xnew, delta, threshold
! mise a jour de xstart
xold = xnew
end do
if (delta < threshold) then
racine = xnew
write(*, *) '--------------------------------------------------------'
write(*, *) ' CONVERGE'
write(*, *) '--------------------------------------------------------'
write(*, *) 'A la convergence demandee, une solution est:'
write(*, "('x = ',e20.10,' f(x) = ', e20.10)") racine, f(racine)
write(*, *)
else
write(*, *) '--------------------------------------------------------'
write(*, *) ' NON CONVERGE'
write(*, *) '--------------------------------------------------------'
end if
end subroutine newtonRaphson
end module rechercheRacine
这里是主程序中的模块:
program main
! contient la subroutine newtonRaphson
use rechercheRacine
! contient la fonction
use fonction
implicit none
double precision :: racine, eps, cible
! appel de la subroutine newtonRaphson
! sans la valeur cible : cible (defaut = 0)
! sans la precision : eps (defaut 1d-10)
racine = 1.d0
call newtonRaphson(racine, unefonction)
! --------------------------------------------------------
! appel de la subroutine newtonRaphson
! avec pour cible 10
racine = 1.d0
eps = 1.d-14
cible = 10.d0
call newtonRaphson(racine, unefonction, eps, cible)
! --------------------------------------------------------
! parametre de la gaussienne
f_sigma = 2.d0
f_mu = 5.d0
! appel de la subroutine newtonRaphson
! passage des arguments sous la forme clef = valeur
cible = 0.1d0
racine = 2.d0
call newtonRaphson(cible = cible, f = gaussienne, racine = racine)
end program main
主程序适用于称为unefonction
的功能,但它不适用于gaussienne
功能。
以下是错误消息:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7F1B6F5890F7
#1 0x7F1B6F5896D4
#2 0x7F1B6EEEB49F
#3 0x4009D2 in __fonction_MOD_gaussienne at mod_fonction.f90:54
#4 0x40104D in __rechercheracine_MOD_newtonraphson at mod_racine.f90:59
#5 0x4016BA in MAIN__ at main.f90:40
Erreur de segmentation (core dumped)
我认为invalid memory reference
是由于这样的事实,该方案确实好像可选参数sig
和mu
存在,从而寻找他们,而他们不是。
是的,问题是你传递的函数确实需要三个参数而不是一个。如果您在子程序newtonRaphson
double precision, external :: f
改变external
声明f
以显式接口(描述,如何真正使用它):
interface
double precision function f(x)
double precision, intent(in) :: x
end function f
end interface
你的代码甚至不会编译由于参数数量不匹配。
他们不同的方式来传递“参数”的功能f
这是从常规newtonRaphson
叫:
-
你可以期望
f
有两个intent(in)
参数,而不是一个:附加到值x ,它也可能需要一个真实的数组,它可以是任意大小的,并且可以包含必要的参数。这需要以下接口:interface double precision function f(x, params) double precision, intent(in) :: x double precision, intent(in) :: params(:) end function f end interface
这些功能,它不需要参数(如
unefonction
)将只是没有使用第二个参数的内容,而其他(如gaussienne
)将持有它们的参数从它。 -
您可以使
newtonRaphson
预期给定的可扩展类型(class
)和一个类型绑定过程返回给定x值的值。然后,您可以创建这种类型的abritrary扩展,它可以基于存储为扩展类型中的字段的一些参数来计算给定x值的值。然后该程序可能看起来像下面(我剥几个部分),但它需要的Fortran编译器2003:module rechercheRacine implicit none type, abstract :: calculator contains procedure(getvalue_iface), deferred :: getvalue end type calculator interface double precision function getvalue_iface(self, x) import :: calculator class(calculator), intent(in) :: self double precision, intent(in) :: x end function getvalue_iface end interface contains subroutine newtonRaphson(racine, f, eps, cible) double precision, intent(inout) :: racine class(calculator), intent(in) :: f double precision, intent(in), optional :: cible, eps do while (delta > threshold .and. compteur <= 100) fdex = f%getvalue(xold) - valcible : end do end subroutine newtonRaphson end module rechercheRacine module fonction use rechercheRacine implicit none type, extends(calculator) :: unefonction contains procedure :: getvalue => unefonction_getvalue end type unefonction type, extends(calculator) :: gaussienne double precision :: mu = 0.0d0, sigma = 1.0d0 contains procedure :: getvalue => gaussienne_getvalue end type gaussienne contains double precision function unefonction_getvalue(self, x) class(unefonction), intent(in) :: self double precision, intent(in) :: x unefonction_getvalue = (exp(x) - 10.)/(x + 2.) end function unefonction_getvalue double precision function gaussienne_getvalue(self, x) class(gaussienne), intent(in) :: self double precision, intent(in) :: x : gaussienne_getvalue = norme * exp(-(x - moy)**2/(2.d0 * self%sigma**2)) end function gaussienne_getvalue end module fonction program main use rechercheRacine use fonction implicit none type(unefonction) :: fone type(gaussienne) :: fgauss : call newtonRaphson(racine, fone) call newtonRaphson(cible = cible, f = fgauss, racine = racine) end program main
尼斯的答案。实际上,外部声明只是我原谅删除的一个测试。我认为如果一个函数/子程序在一个模块中,则会自动创建一个显式接口。我错了吗 ?但我明白,外部声明将删除接口。 我认为参数sig和mu的可选声明是我没有在编译时出错的原因。 – Ger 2013-02-25 22:11:51