将函数作为参数传递给子例程时出现分段错误 [英] Segmentation fault when passing a function as argument in a subroutine
问题描述
我尝试说明如何将函数传递给Newton Raphson过程。我用一个非常简单的函数(称为 unefonction
见下文)成功,但它不适用于具有参数的函数。第二个函数称为 gaussienne
,它有一个参数x和两个可选参数 mu
和 SIG
。在我的牛顿raphson程序中,我以这种方式调用函数: f(x)
。对我来说奇怪的是,在执行过程中,程序就好像可选参数 sig
和 mu
一样但他们不......因此我不明白...
这里是包含函数的模块
模块函数
隐式无
! parametre pour la gaussienne
double precision :: f_sigma = 1.d0,f_mu = 0.d0
! pi可访问唯一性en interne
double precision,parameter :: pi = 3.14159265359d0
包含
双精度函数unefonction(x)
! fonction:unefonction
! renvoie
! $ \frac {e ^ x - 10} {x + 2}
隐式无
!参数
双精度,意图(in):: x
unefonction =(exp(x) - 10.)/(x + 2)
结束函数unefonction
! * * * * * * * * * * * * * * * * * * * * * * * *
双精度函数gaussienne(x,mu,sig)
! fonction gaussienne
!利用参数定义模块si
! mu et sig ne sont pas pass en参数
隐含无
!参数
双精度,意图(in):: x
双精度,意图(in),可选:: mu,sig
!变量locales
双精度:: norme,moy,sigma
! sigma
if(present(sig))then
write(*,*)sig present
sigma = sig
else
sigma = f_sigma
结束如果
!如果(现在(亩)),那么
写(*,*)mu present
moy = mu
else
moy = f_mu
结束如果
! calcul de la gaussienne
norme = 1.d0 /(sigma * sqrt(2.d0 * pi))
gaussienne = norme * exp( - (x - moy)** 2 /(2.d0 * sigma ** 2))
结束函数gaussienne
结束模块函数
以下是包含newton raphson过程的模块
模块rechercheRacine
隐式无
包含
子程序newtonRaphson(racine,f,eps,cible)
! recherche l'antecedant de cible
隐含无
!参数
双精度,意图(inout):: racine
双精度,intent(in),可选:: cible,eps
! fonction不要在cherche la racine
双精度,外部:: f
!变量locales
integer :: compteur
双精度:: xold,xnew,delta,valcible
双精度::阈值,fprim,fdex
!如果(当前(eps))然后
阈值= eps
其他
阈值= 1.d-10
结束,如果
!价值圣经
if(present(cible))then
valcible = cible
else
valcible = 0.d0
如果
写完(*,*)-------------------------------------------- ------------
写入(*,*)NEWTON RAPHSON
写入(*,*)------------ --------------------------------------------
写入(*,('x0 =',e16.6))racine
write(*,('seuil =',e16.6))threshold
write(*, cible =',e16.6))valcible
write(*,*)---------------------------- ----------------------------
write(*,*)ITERATIONS
write(*, *)----------------------------------------------- ---------
!初始化
compteur = 0
delta = 1.d0
xold = racine
write(*,'(i4,4e16.6)')compteur,f(xold),xold ,0.,阈值
!迭代
在(delta>阈值和。compteur< = 100)时执行
!计算结果en bold
fdex = f(xold) - 强迫
! calcul de la derivee numerique
fprim =(f(xold + threshold) - f(xold - threshold))/(2.d0 * threshold)
!应用程序代码Newton Raphson
xnew = xold - fdex / fprim
delta = abs(xnew - xold)
compteur = compteur + 1
! (*,'(i4,4e16.6)')compteur,fdex,xnew,delta,threshold
!如果(delta <阈值),则
racine = xnew
write(*,* b *)如果(delta <阈值)则b $ b = xnew
end do
)'------------------------------------------------ --------'
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(*,*)'------------------------ ------------------------------'
写(*,*)'NON CONVERGE'
write(*,*)'------------------------------------------ --------------'
结束如果
结束子程序newtonRa phson
结束模块rechercheRacine
以下是主程序:
程序主体
!使用rechercheRacine
! contient la fonction
使用功能
隐含无
双精度:: racine,eps,cible
! appel de la子程序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子程序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子程序newtonRaphson
!通过des论证sous la forme clef = valeur
cible = 0.1d0
racine = 2.d0
call newtonRaphson(cible = cible,f = gaussienne,racine = racine)
end program main
主程序适用于名为 unefonction的函数
但它不适用于 gaussienne
函数。
这是错误消息:
编程接收到的信号SIGSEGV:分段错误 - 无效的存储器引用。
Backtrace for this error:
#0 0x7F1B6F5890F7
#1 0x7F1B6F5896D4
#2 0x7F1B6EEEB49F
#3 0x4009D2在__fonction_MOD_gaussienne at mod_fonction.f90:54
#4 0x40104D在__rechercheracine_MOD_newtonraphson在mod_racine.f90:59
#5 0x4016BA在MAIN__在main.f90:40
Erreur de分段(核心转储)
我认为无效的内存引用
是由于程序确实如此可选参数 sig
和 mu
已存在,因此可以查找这些参数。
是的,问题是你传递的函数确实需要三个参数而不是一个。如果在子例程 newtonRaphson
中更改外部
声明 f
>
double precision,external :: f
转换为一个显式接口(描述如何使用它):
接口
双精度函数f(x)
双精度,意图(in):: x
结束函数f
结束接口
由于参数数目不匹配,您的代码甚至无法编译。
它们是将参数传递给从例程
newtonRaphson
调用的函数f
的不同方法:
-
您可以期望
f
有两个intent( in)
参数而不是一个:除了值x之外,它还可以使用一个真正的数组,它可以是任意大小,并且可以包含必要的参数。这将需要以下接口:
接口
双精度函数f(x,params)
双精度,intent(in):: x
双精度,intent(in):: params(:)
结束函数f
结束接口
这些不需要参数的函数(如
unefonction
)不会使用第二个参数,而其他的参数(如gaussienne
)将从它们的参数中获取参数。newtonRaphson
用一个类型绑定过程返回给定x值的值给定可扩展类型(class
) 。然后,您可以创建这种类型的abritrary扩展,它可以基于存储为扩展类型中的字段的一些参数来计算给定x值的值。然后该程序可能如下所示(我剥离了几个部分),但它需要Fortran 2003编译器:module rechercheRacine
隐式无
类型,抽象::计算器
包含
过程(getvalue_iface),deferred :: getvalue
结束类型计算器
接口
双精度函数getvalue_iface(self,x)
import :: calculator $ b $ class(calculator),intent(in):: self
double precision,intent(in) :: x
结束函数getvalue_iface
结束接口
包含
子程序newtonRaphson(racine,f,eps,cible)
双精度,intent(inout):: racine
class(计算器),intent(in):: f
双精度,intent(in),可选:: cible,eps
(delta>阈值,并且compteur< = 100)
fdex = f%getvalue(xold) - 有价值的
:
结束做
结束子程序newtonRaphson
结束模块rechercheRacine
模块函数
使用rechercheRacine
隐式无
类型,扩展(计算器):unefonction
包含
过程:: getvalue => unefonction_getvalue
结束类型unefonction
类型,extends(计算器):: gaussienne
双精度:: mu = 0.0d0,sigma = 1.0d0
包含
procedure :: getvalue => gaussienne_getvalue
结束类型gaussienne
包含
双精度函数unefonction_getvalue(self,x)
class(unefonction),intent(in):: self
double precision,intent(in):: x
unefonction_getvalue =(exp(x) - 10.)/(x + 2)
结束函数unefonction_getvalue
双精度函数gaussienne_getvalue(self,x)
class(gaussienne),intent(in):: self
双精度,intent(in):: x
:
gaussienne_getvalue = norme * exp( - (x - moy)** 2 /(2.d0 * self%sigma ** 2))
结束函数gaussienne_getvalue
结束模块功能
程序主体
使用rechercheRacine
使用功能
隐含无
类型(unefonction):: fone
type(gaussienne):: fgauss
:
call newtonRaphson(racine,fone)
call newtonRaphson(cible = cible,f = fgauss,racine = racine )
结束程序主要
I try to illustrate how to pass a function to a Newton Raphson procedure. I succeed with a very simple function (called unefonction
see below) but it does not work with a function which has got parameters. This second fonction is called gaussienne
and it takes one argument, x, and two optional arguments mu
and sig
. In my newton raphson procedure I called the fonction in this way : f(x)
. What is strange for me is that during the execution, the program does as if the optional parameters sig
and mu
were present but they don't... Thus I do not understand ...
Here is the module which contains the functions
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
Here is the module which contains the newton raphson procedure
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
Here is the main program :
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
The main program works for the function called unefonction
but it doesn't work for the gaussienne
function.
Here is the error message :
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)
I think that the invalid memory reference
is due to the fact that the program does as if optional parameters sig
and mu
were present and thus looks for them while they are not.
Yes, the problem is that the function you pass indeed expects three arguments instead of one only. If you change the external
declaration of f
in the subroutine newtonRaphson
double precision, external :: f
to an explicit interface (which describes, how you really use it):
interface
double precision function f(x)
double precision, intent(in) :: x
end function f
end interface
your code won't even compile due to the mismatch in the number of parameters.
They are different ways to pass "parameters" to the function f
which is called from the routine newtonRaphson
:
You could expect
f
to have twointent(in)
arguments instead of one: Additional to the value x, it could take also a real array, which may be of arbitrary size and may contain the necessary parameters. That would require following interface:interface double precision function f(x, params) double precision, intent(in) :: x double precision, intent(in) :: params(:) end function f end interface
Those functions, which do not need parameters (like
unefonction
) would just not use the content of the second parameter, while others (likegaussienne
) would take their parameters from it.You could make
newtonRaphson
to expect a given extensible type (class
) with a type bound procedure returning the value for a given x-value. You can then create abritrary extensions of this type, which may calculate the value for the given x-value based on some parameters stored as fields in the extended type. Then the program could look like below (I stripped several parts), but it would require Fortran 2003 compiler: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
这篇关于将函数作为参数传递给子例程时出现分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!