2

Newton Raphson プロシージャに関数を渡す方法を説明しようとしました。unefonction非常に単純な関数 (以下を参照) で成功しましたが、パラメーターを持つ関数では機能しません。この 2 番目の関数が呼び出されgaussienne、1 つの引数 x と 2 つのオプション引数muandを取りますsig。私のニュートンラフソン手順では、関数を次のように呼び出しましたf(x)。私にとって奇妙なのは、実行中にプログラムがオプションのパラメーターsigmuが存在するかのように動作することですが、それらは存在しません...したがって、私は理解できません...

これが関数を含むモジュールです

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これは、プログラムがオプションのパラメーターsigmu存在するかのように動作し、存在しないときにそれらを検索するためだと思います。

4

1 に答える 1

7

はい、問題は、渡す関数が実際に 1 つだけではなく 3 つの引数を期待していることです。サブルーチン内のexternal宣言を変更するとfnewtonRaphson

double precision, external :: f

明示的なインターフェース(実際にどのように使用するかを説明します):

interface
  double precision function f(x)
    double precision, intent(in) :: x
  end function f
end interface

パラメーターの数が一致しないため、コードはコンパイルされません。

fこれらは、ルーチンから呼び出される関数に「パラメーター」を渡すさまざまな方法ですnewtonRaphson

  • f1 つではなく2 つの引数を持つことが期待できます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) は 2 番目のパラメーターの内容を使用しないだけで、他の関数 ( などgaussienne) はそこからパラメーターを取得します。

  • 指定された x 値の値を返す型バインド プロシージャを使用newtonRaphsonして、指定された拡張可能な型 ( ) を期待するようにすることができます。classその後、拡張型のフィールドとして格納されたいくつかのパラメーターに基づいて、指定された 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
    
于 2013-02-25T21:53:12.893 に答える