函数列表和分段错误 - 无效的内存引用 [英] Array of functions and Segmentation fault - invalid memory reference

查看:239
本文介绍了函数列表和分段错误 - 无效的内存引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将我的函数 f 设置为一个数组,但是我得到以下错误:

 编程接收到的信号SIGSEGV:分段错误 - 无效的存储器引用。 

回溯此错误:

#0 0x6f8b36e3
#1 0x6f8a2722
#2 0x402752
#3 0x747bd411

我必须求解开普勒方程: f = psi-e * sin(psi)-M 对于每个值 M 。因此,如果我有一个8维的数组 M ,我的程序将计算8个零。问题是,如果我写 f = psi-e * sin(psi)-M(1),我会计算第一个零,如果我写 f = psi -e * sin(psi)-M(8)我会计算最后一个零。但是,我的问题是如果我想一次计算所有的零,必须写 f = psi-e * sin(psi)-M(1:8),我的程序应该输入全零,但是,这并不会发生,我得到错误,我前面提到过。这里是代码:

SUBROUTINE(我使用EXTERNALLY):这个子程序是二等分方法(获得零):

 子程序bisecc(f,xl,xr,kmax,tol,k,xm)
隐式实数* 8(ah,oz)
real * 8 f
fl = f(xl)
fr = f(xr)

if(fl * fr .gt。0.0D0)goto 100 $ b $ (xr-xl)/ xm(xr-xl)/ bm(xr-xl)b bm =(xr + xl)/2.0D0
fm = f(xm)

$ = )
if(dif .lt。tol)goto 200
write(*,*)k,xm!,dif
if(fm * fr .le。0.0D0)then
xl = xm
fl = fm
else
xr = xm
fr = fm
end if
end do

return
200 write(*,*)'WISHED PRECISION REACHED '
return
100 write(*,*)'BAD CHOICE OF DATA'
return
end

主程序:

 包含'bisecc.f'
隐含真实* 8(啊,盎司)
外部f
真实* 8 f
!我写了8个ZEROS的区间(左右点)
b = 0.1D0


xl1 = -0.5D0
xr1 = 0.D0
xl2 = xr1 + b
xr2 = 1.D0
xl3 = xr2 + b
xr3 = 2.D0
xl4 = xr3 + b
xr4 = 3。 D0
xl5 = xr4 + b
xr5 = 4.D0
xl6 = xr5 + b
xr6 = 5.D0
xl7 = xr6 + b
xr7 = 6.D0
xl8 = xr7 + b
xr8 = 7.D0
kmax = 100
tol = 0.0001D0
call bisecc(f,xl1,xr1 ,KMAX,TOL,K,XM1)
呼叫bisecc(F,XL2,XR2,KMAX,TOL,K,XM2)
呼叫bisecc(F,XL3,XR3,KMAX,TOL,K,XM3 )
call bisecc(f,xl4,xr4,kmax,tol,k,xm4)
call bisecc(f,xl5,xr5,kmax,tol,k,xm5)
call bisecc女,×16,XR6,KMAX,TOL,K,XM6)
呼叫bisecc(F,XL7,XR7,KMAX,TOL,K,XM7)
呼叫bisecc(F,×18,XR8,KMAX, tol,k,xm8)
write(*,*)'Program ended'
stop
end program






<$ p (8)
实数* 8(8)
实数* 8函数f(psi)
隐式实数* 8
e = 0.2056D0
pi = acos(-1.0D0)
M =(/ pi / 4.D0,pi / 2.D0,3.D0 / 4.D0 * pi,pi ,5.D0 / 4.D0 * pi,3.D0 *
& pi / 2.D0,7.D0 / 4.D0 * pi,2.D0 * pi /)
c = sqrt((1.0D0-e)/(1.0D0 + e))
f = psi -e * sin(psi)-M(1:8)!KEPLER EQUATION

return
end function

举例:
在这里,我想计算第一个M值的psi值, M(1)= pi / 4





上面的代码还有很多要改进的地方。特别是,将一个像 f()这样的函数包含到模块中(或者甚至将所有例程包含到模块中)通常更方便。我们也可以通过将 M 作为模块变量,使用它从 f() (而不是使用 common 语句)或通过主机关联,所以如果感兴趣请尝试。


I am trying to set my function f as an array, but I get the following error:

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:

#0  0x6f8b36e3
#1  0x6f8a2722
#2  0x402752
#3  0x747bd411

I have to solve the Kepler's equation:f=psi-e*sin(psi)-M for each value of M.So, if I have an array M of dimension 8, my program will calculate 8 zeros. The thing is that, if I write f=psi-e*sin(psi)-M(1) I will calculate the first zero,and if I write f=psi-e*sin(psi)-M(8) I will calculate the last zero.But ,my problem is that if I want to calculate all zeros at once, I would have to write f=psi-e*sin(psi)-M(1:8) and my program should type all zeros, but,that doesnt happen and i get the error i mentioned earlier.Here is the code:

SUBROUTINE (I USED EXTERNALLY):This subroutine is the bisection method (to get zeros):

   subroutine bisecc(f,xl,xr,kmax,tol,k,xm)
  implicit real*8 (a-h,o-z)
  real*8 f
  fl=f(xl)
  fr=f(xr)

  if(fl*fr .gt. 0.0D0) goto 100  
  do k=1,kmax
    xm=(xr+xl)/2.0D0              
    fm=f(xm)

    dif=abs((xr-xl)/xm)        
    if(dif .lt. tol) goto 200    
    write(*,*) k,xm!,dif  
    if (fm*fr .le. 0.0D0) then
      xl=xm
      fl=fm
    else
      xr=xm
      fr=fm
    end if
  end do

  return
200   write(*,*) 'WISHED PRECISION  REACHED'
      return
100   write(*,*) 'BAD CHOICE OF DATA'
      return
      end

MAIN PROGRAM:

       include 'bisecc.f' 
   implicit real*8 (a-h,o-z)            
   external f     
   real*8 f    
   ! I  WRITE  THE INTERVAL OF MY 8 ZEROS(left and right point)
   b=0.1D0


   xl1=-0.5D0                
   xr1=0.D0                 
   xl2=xr1+b
   xr2=1.D0
   xl3=xr2+b
   xr3=2.D0
   xl4=xr3+b
   xr4=3.D0
   xl5=xr4+b
   xr5=4.D0
   xl6=xr5+b
   xr6=5.D0
   xl7=xr6+b
   xr7=6.D0
   xl8=xr7+b
   xr8=7.D0        
   kmax=100                            
   tol=0.0001D0                               
   call bisecc(f,xl1,xr1,kmax,tol,k,xm1)         
   call bisecc(f,xl2,xr2,kmax,tol,k,xm2)          
   call bisecc(f,xl3,xr3,kmax,tol,k,xm3)         
   call bisecc(f,xl4,xr4,kmax,tol,k,xm4)         
   call bisecc(f,xl5,xr5,kmax,tol,k,xm5)         
   call bisecc(f,xl6,xr6,kmax,tol,k,xm6)         
   call bisecc(f,xl7,xr7,kmax,tol,k,xm7)          
   call bisecc(f,xl8,xr8,kmax,tol,k,xm8)                     
   write(*,*) 'Program ended'
   stop
   end program


   real*8 function f(psi)
   implicit real*8 (a-h,o-z)
   real*8 M(8)
   dimension f(8)
      e=0.2056D0                          
      pi=acos(-1.0D0)                        
      M=(/pi/4.D0,pi/2.D0,3.D0/4.D0*pi,pi,5.D0/4.D0*pi,3.D0*
 &    pi/2.D0,7.D0/4.D0*pi,2.D0*pi/)
      c=sqrt((1.0D0-e)/(1.0D0+e))                
   f=psi-e*sin(psi)-M(1:8)             !KEPLER EQUATION

   return
   end function   

EXAMPLE: Here I wanted to calculate the value of psi for the first value of M, M(1)=pi/4.

In http://imgur.com/a/Xdsgf you can see that psi=0.95303344726562489. So I have just calculated the first zero. But, you can also see this message 7 times datos mal elegidos. It means that the program can only show me that zero (for M(1)), and the other 7 zeros are not calculated, because I wrote f=psi-e*sin(psi)-M(1). What should I write so I can get the result of all zeros instead of 1, like in this example?

解决方案

Because the function f() is used in the bisection routine bisecc(), I think it would be much simpler to pass each input to bisecc() via a DO loop, rather than making f() a function returning an array (because the latter requires to modify bisecc() also). We can pass the value of M to f() in various ways (which is almost FAQ and I believe there are a lot of Q/A pages). One simple way is to contain f() in the main program and use host association for M. So a simplified code may look like

program main
    implicit none
    integer  kmax, kiter, i
    real*8   xl( 8 ), xr( 8 ), xans( 8 ), tol, M( 8 ), b, pi

    pi   = acos(-1.0D0)                 
    kmax = 100
    tol  = 1.0d-8

    M = [ pi/4.D0,      pi/2.D0,      3.D0/4.D0*pi, pi, &
          5.D0/4.D0*pi, 3.D0*pi/2.D0, 7.D0/4.D0*pi, 2.D0*pi ]
    ! or M = [( i, i=1,8 )] * pi/4.0D0

    ! Use a fixed interval for simplicity.
    xl   =  0.0d0
    xr   = 10.0d0
    xans =  0.0d0

    do i = 1, 8
        call bisecc( f, xl( i ), xr( i ), kmax, tol, kiter, xans( i ) )
        ! print *, "check: f(xans(i)) = ", f( xans( i ) )
    enddo

contains

function f( psi ) result( res )
    implicit none
    real*8  psi, e, res
    e = 0.2056D0
    res = psi - e * sin( psi ) - M( i )   !<-- this "M(i)" refers to that defined above
end function 

end program

with an external bisecc routine (a little modified so as not to use GOTO)

subroutine bisecc( f, xl, xr, kmax, tol, k, xm )
    implicit none
    real*8  f, xl, xr, tol, xm
    external f
    integer kmax, k
    real*8  fl, fr, fm, dif

    fl = f( xl )
    fr = f( xr )
    if( fl * fr > 0.0D0 ) then
        write(*,*) "bad input data (xl,xr)"
        return
    endif

    do k = 1, kmax
        xm = (xr + xl) / 2.0D0              
        fm = f( xm )

        dif = abs( (xr-xl) / xm )
        if ( dif < tol ) then
            write(*,*) "bisection converged: k=", k, "xm=", xm
            return
        endif

        if ( fm * fr <= 0.0D0 ) then
            xl = xm
            fl = fm
        else
            xr = xm
            fr = fm
        end if
    end do  !! iteration

    write(*,*) "bisection did not converge: k=", k, "xm=", xm
end

which gives

 bisection converged: k=          31 xm=  0.95299366395920515     
 bisection converged: k=          31 xm=   1.7722388869151473     
 bisection converged: k=          30 xm=   2.4821592587977648     
 bisection converged: k=          30 xm=   3.1415926571935415     
 bisection converged: k=          29 xm=   3.8010260276496410     
 bisection converged: k=          29 xm=   4.5109464414417744     
 bisection converged: k=          29 xm=   5.3301916457712650     
 bisection converged: k=          29 xm=   6.2831853143870831

The answer seems to agree with the plot of the Kepler equation with e = 0.2056 (so bisecc() is probably OK).

The above code still has a lot of points for improvement. In particular, it is usually more convenient to include a function like f() into a module (or even include all routines into a module). We can also pass M by making it a module variable and use it from f() (rather than using common statements) or via host association, so please try it if interested.

这篇关于函数列表和分段错误 - 无效的内存引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆