Polynomial Zeros in Quadruple Precision
February 28, 2013
I host an archive of Alan Miller’s Fortran Software, a large collection of routines from a wide range of fields. My goal is simply to make sure these algorithms remain easily accessible, not to actively maintain or enhance them. Occasionally though, users of these algorithms contact me with improvements that others may find useful.
In particular, N. Shamsundar wrote to me to regarding an improvement to rpoly.f90, a Fortran implementation of the Jenkins-Traub algorithm for finding zeros of polynomials. If you use this algorithm and your compiler supports quadruple precision, then you may be interested in making the changes described in his comments below.
I am writing about a suggested enhancement to
rpoly.f90
. This routine returns the zeros of a polynomial with real coefficients. Run as is, for the test examples it produces these results:EXAMPLE 1. POLYNOMIAL WITH ZEROS 1,2,...,10. Real part Imaginary part 1.00000000250611 0.00000000000000 2.00002883224649 0.00000000000000 2.99991349226559 0.00000000000000 4.00008651702092 0.00000000000000 4.99997115596089 0.00000000000000 EXAMPLE 2. POLYNOMIAL WITH ZEROS 1,2,...,10. Real part Imaginary part 1.00000000236858 0.00000000000000 2.00002195897130 0.00000000000000 3.00046637606344 0.00000000000000 3.99858534914590 0.00000000000000 5.01275188243750 0.00000000000000 5.94435077376986 0.00000000000000 7.13492931078591 0.00000000000000 7.85730317747578 0.00000000000000 9.06783881447278 0.00000000000000 9.98375235450897 0.00000000000000 Now try case where 1 is an obvious root Real part Imaginary part -0.283274635857482E-05 1.00000686290706 -0.283274635857482E-05 -1.00000686290706 0.283307420786060E-05 0.999993137276023 0.283307420786060E-05 -0.999993137276023 0.999999999344302 0.00000000000000
For Example 2 the polynomial is (x–1).(x–2)…(x–10), and the results are somewhat inaccurate. I believe that the cause is the lower precision of the IEEE floating point arithmetic that is implemented in modern microprocessors as compared to the BURROUGHS B6700 mentioned in the original F77 program of Jenkins and Traub, http://www.netlib.org/toms/493.
The following minor changes enable the results to be improved considerably if the compiler supports quadruple precision, as do Gfortran, Intel and Absoft.
In Subroutine RPOLY, at line–73, change the value assigned to
ETA
to1D-20
.In Subroutine
REALIT
, line–500 of the file, change the type of variablepv
toREAL*16
orkind=selected_real_kind(30,300)
, whichever is supported by the compiler. I suggestREAL*16
; if the user’s compiler objects to it, the user can change it to suit.After these modifications, the results become:
EXAMPLE 1. POLYNOMIAL WITH ZEROS 1,2,...,10. Real part Imaginary part 1.00000000000000 0.00000000000000 2.00000000000000 0.00000000000000 3.00000000000000 0.00000000000000 4.00000000000000 0.00000000000000 5.00000000000000 0.00000000000000 EXAMPLE 1. POLYNOMIAL WITH ZEROS 1,2,...,10. Real part Imaginary part 1.00000000000000 0.00000000000000 2.00000000000000 0.00000000000000 3.00000000000000 0.00000000000000 4.00000000000000 0.00000000000000 5.00000000000013 0.00000000000000 5.99999999999862 0.00000000000000 7.00000000000477 0.00000000000000 7.99999999999255 0.00000000000000 9.00000000000543 0.00000000000000 9.99999999999849 0.00000000000000 Now try case where 1 is an obvious root Real part Imaginary part -0.333797545686623E-09 1.00000000007661 -0.333797545686623E-09 -1.00000000007661 0.333797544801067E-09 0.999999999923389 0.333797544801067E-09 -0.999999999923389 1.00000000000000 0.00000000000000
I should note that there is also a quadruple precision version of this algorithm in the archive, q_rpoly.f90, but that version makes use of software-implemented quadruple precision via the module in quad.f90, which is slower than native quadruple precision.