Array of functions and Segmentation fault - invalid memory reference

…衆ロ難τιáo~ 提交于 2019-12-02 13:13:50
roygvib

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.

MY SOLUTION:I will add a more generic solution to my exercise,avoiding the mentioned error.This is a more generic solution,for N values of M,instead of 8:

   include 'bisecc.f'  
   implicit real*8 (a-h,o-z)             
   external f     
   parameter (Mlong=100)              !Number of elemnts of M(from 0 to 2pi)
   real*8 f ,M                               
   common M,e                         !to not copy them twice 

   kmax=100                           !max number of iterations
   tol=0.0001D0                       !Tolerance of 0.01%
   e=0.2056D0                         !Mercury excentricity
   pi=acos(-1.0D0)                     
   c=sqrt((1.0D0-e)/(1.0D0+e))     

   open(10,file='153b.dat',status='unknown') !data will apear in a .dat file
   write(*,*)'            i        M                 Theta(rad)'
   write(10,*)'           i        M                 Theta(rad)'

  do i=1,Mlong
     xl=-1.D0                     !LEFT STARTING POINT
     xr=7.D0                      !RIGHT POINT(psi wont be more than 2*pi)  
     M=2.D0*pi*i/Mlong                         !GENERIC M(0 TO 2PI 100STEPS) 
     call bisecc(f,xl,xr,kmax,tol,k,xm)        !CALLING THE SUBROUTINE
     write(10,*) i,M,theta             ! I WILL PLOT THETA IN FUNCTION OF M
     write(*,*) i,M,theta
   end do 

   close(10)
   write(*,*)
   write(*,*) 'Program ENDED'
   stop
   end program

*MY EXTERNAL FUNCTION


   real*8 function f(psi)
   implicit real*8 (a-h,o-z)
   real*8 M
   common M,e
    f=psi-e*sin(psi)-M                       !KEPLER EQUATION
   return       
   end function    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!