Solve for the roots of a real polynomial equation by computing the eigenvalues of the companion matrix.
This one uses LAPACK for the eigen solver (sgeev
or dgeev
).
Note
Works only for single and double precision.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in) | :: | n |
polynomial degree |
||
real(kind=wp), | intent(in), | dimension(n+1) | :: | p |
polynomial coefficients array, in order of decreasing powers |
|
real(kind=wp), | intent(out), | dimension(n) | :: | wr |
real parts of roots |
|
real(kind=wp), | intent(out), | dimension(n) | :: | wi |
imaginary parts of roots |
|
integer, | intent(out) | :: | info |
output from the lapack solver.
|
subroutine polyroots(n, p, wr, wi, info) implicit none integer, intent(in) :: n !! polynomial degree real(wp), dimension(n+1), intent(in) :: p !! polynomial coefficients array, in order of decreasing powers real(wp), dimension(n), intent(out) :: wr !! real parts of roots real(wp), dimension(n), intent(out) :: wi !! imaginary parts of roots integer, intent(out) :: info !! output from the lapack solver. !! !! * if `info=0` the routine converged. !! * if `info=-999`, then the leading coefficient is zero. integer :: i !! counter real(wp), allocatable, dimension(:,:) :: a !! companion matrix real(wp), allocatable, dimension(:) :: work !! work array real(wp), dimension(1) :: vl, vr !! not used here #ifdef REAL32 interface subroutine sgeev(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info) implicit none character :: jobvl, jobvr integer :: info, lda, ldvl, ldvr, lwork, n real :: a(lda, *), vl(ldvl, *), vr(ldvr, *), wi(*), work(*), wr(*) end subroutine sgeev end interface #elif REAL128 ! do not have a quad solver in lapack #else interface subroutine dgeev(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info) implicit none character :: jobvl, jobvr integer :: info, lda, ldvl, ldvr, lwork, n double precision :: a(lda, *), vl(ldvl, *), vr(ldvr, *), wi(*), work(*), wr(*) end subroutine dgeev end interface #endif ! error check: if (abs(p(1)) == 0.0_wp) then info = -999 return end if ! allocate the work array: allocate (work(3*n)) ! create the companion matrix allocate (a(n, n)) a = 0.0_wp do i = 1, n - 1 a(i, i + 1) = 1.0_wp end do do i = n, 1, -1 a(n, n - i + 1) = -p(i + 1)/p(1) end do ! call the lapack solver: #ifdef REAL32 ! single precision call sgeev('N', 'N', n, a, n, wr, wi, vl, 1, vr, 1, work, 3*n, info) #elif REAL128 error stop 'do not have a quad solver in lapack' #else ! by default, use double precision: call dgeev('N', 'N', n, a, n, wr, wi, vl, 1, vr, 1, work, 3*n, info) #endif end subroutine polyroots