Vorige Seite Kein Verweis Übersicht Kein Verweis content index Hilfeseiten  

Berechnung der Nullstellen eines reellen Polynoms

Es sollen die Nullstellen von

nach dem Verfahren von Bairstow bestimmt werden.

Gefundene Nullstellen werden abdividiert und das Verfahren fortgesetzt, bis eine lineare oder quadratische Gleichung übrig bleibt.

Gefundene Nullstellen sind durch Rundungs- und Abbruchfehler u.U. stark verfälscht. Deshalb muss jede Nullstelle nachiteriert werden, z.B. mit dem gewöhnlichem Newtonverfahren.

module mysubs

contains

  subroutine init(a, b, c, n, eps, maxit)
    use kinds
    implicit none
    real(kind=REAL8), dimension(:), pointer :: a, b, c
    integer, intent(out)                    :: n, maxit
    real(kind=REAL8), intent(out)           :: eps

    integer   :: i

    write (*,*) 'Darstellung der Berechnung der Nullstellen eines reellen'
    write (*,*) 'Polynomes mittels des Verfahren von Bairstow'
    write (*,*)

    write (*,*) 'Geben Sie bitte den Grad des Polynoms an'
    read (*,*) n
    allocate (a(0:n))
    allocate (b(0:n))
    allocate (c(0:n))
    do i=0, n
       write (*,*) 'Geben Sie nun den Koeffizienten a(', i, ') an'
       read (*,*) a(i)
    end do

    write (*,*) 'Wie genau sollen die Nullstellen berechnet werden?'
    read (*,*) eps
    do
       if (eps > 0) exit
       write (*,*) 'Nur positive Genauigkeiten machen Sinn. Versuchen Sie &
                   &es noch einmal.'
       read (*,*) eps
    end do

    write (*,*) 'Wieviele Iterationen sollen maximal durchgefuehrt werden?'
    read (*,*) maxit
    do
       if (maxit > 0) exit
       write (*,*) 'Nur positive Werte sind hier vernuenftig. Versuchen &
                   &Sie es noch einmal.'
       read (*,*) maxit
    end do
    return
  end subroutine init

  subroutine loese(r, s)
    use kinds
    implicit none
    real(kind=REAL8), intent(in) :: r, s
    real(kind=REAL8) :: x0, x1

    if (r*r + 4*s < 0) then
       write (*,*) 'Das Polynom hat komplexe Wurzeln.'
       stop
    else
       x0 = r/2.0 - sqrt(r*r/4.0 + s)
       x1 = r/2.0 + sqrt(r*r/4.0 + s)
       write (*, '(F9.5)') x0
       write (*, '(F9.5)') x1
    end if
    return
  end subroutine loese

end module mysubs



program Bairstow
  ! Berechnung der Nullstellen eines reellen Polynoms

  use kinds
  use mysubs
  implicit none

  real(kind=REAL8), dimension(:), pointer :: a, b, c
  integer          :: n, i, deg, iter, maxit
  real(kind=REAL8) :: r, s            ! x^2-rx-s ist ein Teiler des Polynoms
  real(kind=REAL8) :: eps, dr, ds, eps1, eps2, det
  logical          :: abbruch

  call init(a, b, c, n, eps, maxit)
  deg  = n
  iter = 0

  do
     if ((deg <= 2) .or. (iter >= maxit)) exit
     iter = 0
     write (*,*) 'Geben Sie geschaetzte Koeffizienten fuer einen &
                 &quadratischen Teiler des Polynoms an.'
     read (*,*) r, s
     do
        iter = iter + 1
        b(deg)   = a(deg)
        b(deg-1) = a(deg-1) + r*b(deg)
        c(deg)   = b(deg)
        c(deg-1) = b(deg-1) + r*c(deg)
        i = deg - 2
        do
           if (i < 0) exit
           b(i) = a(i) + r*b(i+1) + s*b(i+2)
           c(i) = b(i) + r*c(i+1) + s*c(i+2)
           i = i-1
        end do
        det     = c(2)*c(2) - c(3)*c(1)
        abbruch = (det == 0) .or. (iter > maxit)
        if (.not. abbruch) then
           dr   = (-b(1)*c(2) + b(0)*c(3))/det
           ds   = (-b(0)*c(2) + b(1)*c(1))/det
           eps1 = dr
           eps2 = ds
           r    = r + dr
           s    = s + ds
        end if
        if ( (eps1eps) .or. abbruch) exit
     end do
     if (.not. abbruch) then
        call loese(r, s)
        deg = deg - 2
        do i=0, deg
           a(i) = b(i+2)
        end do
     end if
  end do
  if (iter < maxit) then
     if (deg == 2) then
        r = -a(1)/a(2)
        s = -a(0)/a(2)
        call loese(r, s)
     else
        write (*,*) -a(0)/a(1)
     end if
  else
     write (*,*) 'Es werden zu viele Schritte benoetigt.'
  end if
  stop
end program Bairstow