Subroutine to compute polynomial roots using the Durand-Kerner algorithm. The roots are assumed to be real.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=pfqp), | intent(out) | :: | roots(n) | |||
real(kind=pfqp), | intent(in) | :: | p0(0:n) | |||
integer, | intent(in), | value | :: | n |
subroutine poly_roots(roots, p0, n)
integer, intent(in), value :: n
real(pfqp), intent(out) :: roots(n)
real(pfqp), intent(in) :: p0(0:n)
integer :: i, j, k
complex(pfqp) :: num, den, z0(n), z1(n)
real(pfqp) :: p(0:n)
real(pfqp) :: eps
eps = epsilon(1.0_pfqp)*100.0_pfqp
p = p0 / p0(n)
! initial guess
do i = 1, n
z0(i) = (0.4_pfqp, 0.9_pfqp)**i
end do
! durand-kerner-weierstrass iterations
z1 = z0
do k = 1, 100
do i = 1, n
! evaluate poly at z0(i)
num = poly_eval_complex(p, n, z0(i))
! evaluate denominator
den = 1.0_pfqp
do j = 1, n
if (j == i) cycle
den = den * (z0(i) - z0(j))
end do
! update
z0(i) = z0(i) - num / den
end do
! converged?
if (sum(abs(z0 - z1)) < eps) exit
z1 = z0
end do
roots = real(z0)
where (abs(roots) < eps) roots = 0.0_pfqp
call qsort(roots)
end subroutine poly_roots