@@ -62,6 +62,7 @@ module polyroots_module
6262 ! special polynomial routines:
6363 public :: dcbcrt
6464 public :: dqdcrt
65+ public :: dqtcrt
6566 public :: rroots_chebyshev_cubic
6667
6768 ! utility routines:
@@ -1254,6 +1255,302 @@ pure subroutine dqdcrt(a, zr, zi)
12541255end subroutine dqdcrt
12551256! *****************************************************************************************
12561257
1258+ ! *****************************************************************************************
1259+ ! >
1260+ ! dqtcrt computes the roots of the real polynomial
1261+ ! ```
1262+ ! a(1) + a(2)*z + ... + a(5)*z**4
1263+ ! ```
1264+ ! and stores the results in `zr` and `zi`. it is assumed
1265+ ! that `a(5)` is nonzero.
1266+ !
1267+ ! ### History
1268+ ! * Original version written by alfred h. morris,
1269+ ! naval surface weapons center, dahlgren, virginia
1270+ !
1271+ ! ### See also
1272+ ! * A. H. Morris, "NSWC Library of Mathematical Subroutines",
1273+ ! Naval Surface Warfare Center, NSWCDD/TR-92/425, January 1993
1274+
1275+ subroutine dqtcrt (a ,zr ,zi )
1276+
1277+ real (wp) :: a(5 ) , zr(4 ) , zi(4 )
1278+ real (wp) :: b , b2 , c , d , e , h , p , q , r , t , temp(4 ) , &
1279+ u , v , v1 , v2 , w(2 ) , x , x1 , x2 , x3
1280+
1281+ if ( a(1 )==0.0_wp ) then
1282+ zr(1 ) = 0.0_wp
1283+ zi(1 ) = 0.0_wp
1284+ call dcbcrt(a(2 ),zr(2 ),zi(2 ))
1285+ else
1286+ b = a(4 )/ (4.0_wp * a(5 ))
1287+ c = a(3 )/ a(5 )
1288+ d = a(2 )/ a(5 )
1289+ e = a(1 )/ a(5 )
1290+ b2 = b* b
1291+
1292+ p = 0.5_wp * (c-6.0_wp * b2)
1293+ q = d - 2.0_wp * b* (c-4.0_wp * b2)
1294+ r = b2* (c-3.0_wp * b2) - b* d + e
1295+
1296+ ! solve the resolvent cubic equation. the cubic has
1297+ ! at least one nonnegative real root. if w1, w2, w3
1298+ ! are the roots of the cubic then the roots of the
1299+ ! originial equation are
1300+ !
1301+ ! z = -b + csqrt(w1) + csqrt(w2) + csqrt(w3)
1302+ !
1303+ ! where the signs of the square roots are chosen so
1304+ ! that csqrt(w1) * csqrt(w2) * csqrt(w3) = -q/8.
1305+
1306+ temp(1 ) = - q* q/ 64.0_wp
1307+ temp(2 ) = 0.25_wp * (p* p- r)
1308+ temp(3 ) = p
1309+ temp(4 ) = 1.0_wp
1310+ call dcbcrt(temp,zr,zi)
1311+ if ( zi(2 )/= 0.0_wp ) then
1312+
1313+ ! the resolvent cubic has complex roots
1314+
1315+ t = zr(1 )
1316+ x = 0.0_wp
1317+ if ( t< 0 ) then
1318+ h = abs (zr(2 )) + abs (zi(2 ))
1319+ if ( abs (t)>h ) then
1320+ v = sqrt (abs (t))
1321+ zr(1 ) = - b
1322+ zr(2 ) = - b
1323+ zr(3 ) = - b
1324+ zr(4 ) = - b
1325+ zi(1 ) = v
1326+ zi(2 ) = - v
1327+ zi(3 ) = v
1328+ zi(4 ) = - v
1329+ return
1330+ endif
1331+ elseif ( t/= 0 ) then
1332+ x = sqrt (t)
1333+ if ( q> 0.0_wp ) x = - x
1334+ endif
1335+ w(1 ) = zr(2 )
1336+ w(2 ) = zi(2 )
1337+ call dcsqrt(w,w)
1338+ u = 2.0_wp * w(1 )
1339+ v = 2.0_wp * abs (w(2 ))
1340+ t = x - b
1341+ x1 = t + u
1342+ x2 = t - u
1343+ if ( abs (x1)>abs (x2) ) then
1344+ t = x1
1345+ x1 = x2
1346+ x2 = t
1347+ endif
1348+ u = - x - b
1349+ h = u* u + v* v
1350+ if ( x1* x1< 1.0e-2_wp * min (x2* x2,h) ) x1 = e/ (x2* h)
1351+ zr(1 ) = x1
1352+ zr(2 ) = x2
1353+ zi(1 ) = 0.0_wp
1354+ zi(2 ) = 0.0_wp
1355+ zr(3 ) = u
1356+ zr(4 ) = u
1357+ zi(3 ) = v
1358+ zi(4 ) = - v
1359+
1360+ else
1361+
1362+ ! the resolvent cubic has only real roots
1363+ ! reorder the roots in increasing order
1364+ x1 = zr(1 )
1365+ x2 = zr(2 )
1366+ x3 = zr(3 )
1367+ if ( x1> x2 ) then
1368+ t = x1
1369+ x1 = x2
1370+ x2 = t
1371+ endif
1372+ if ( x2> x3 ) then
1373+ t = x2
1374+ x2 = x3
1375+ x3 = t
1376+ if ( x1> x2 ) then
1377+ t = x1
1378+ x1 = x2
1379+ x2 = t
1380+ endif
1381+ endif
1382+
1383+ u = 0.0_wp
1384+ if ( x3> 0.0_wp ) u = sqrt (x3)
1385+ tmp : block
1386+ if ( x2<= 0.0_wp ) then
1387+ v1 = sqrt (abs (x1))
1388+ v2 = sqrt (abs (x2))
1389+ if ( q< 0.0_wp ) u = - u
1390+ else
1391+ if ( x1< 0.0_wp ) then
1392+ if ( abs (x1)>x2 ) then
1393+ v1 = sqrt (abs (x1))
1394+ v2 = 0.0_wp
1395+ exit tmp
1396+ else
1397+ x1 = 0.0_wp
1398+ endif
1399+ endif
1400+ x1 = sqrt (x1)
1401+ x2 = sqrt (x2)
1402+ if ( q> 0.0_wp ) x1 = - x1
1403+ zr(1 ) = ((x1+ x2)+ u) - b
1404+ zr(2 ) = ((- x1- x2)+ u) - b
1405+ zr(3 ) = ((x1- x2)- u) - b
1406+ zr(4 ) = ((- x1+ x2)- u) - b
1407+ call daord(zr,4 )
1408+ if ( abs (zr(1 ))<0.1_wp * abs (zr(4 )) ) then
1409+ t = zr(2 )* zr(3 )* zr(4 )
1410+ if ( t/= 0.0_wp ) zr(1 ) = e/ t
1411+ endif
1412+ zi(1 ) = 0.0_wp
1413+ zi(2 ) = 0.0_wp
1414+ zi(3 ) = 0.0_wp
1415+ zi(4 ) = 0.0_wp
1416+ return
1417+ endif
1418+ end block tmp
1419+ zr(1 ) = - u - b
1420+ zi(1 ) = v1 - v2
1421+ zr(2 ) = zr(1 )
1422+ zi(2 ) = - zi(1 )
1423+ zr(3 ) = u - b
1424+ zi(3 ) = v1 + v2
1425+ zr(4 ) = zr(3 )
1426+ zi(4 ) = - zi(3 )
1427+ endif
1428+
1429+ endif
1430+
1431+ end subroutine dqtcrt
1432+ ! *****************************************************************************************
1433+
1434+ ! *****************************************************************************************
1435+ ! >
1436+ ! Used to reorder the elements of the double precision
1437+ ! array a so that abs(a(i)) <= abs(a(i+1)) for i = 1,...,n-1.
1438+ ! it is assumed that n >= 1.
1439+
1440+ subroutine daord (a ,n )
1441+
1442+ integer ,intent (in ) :: n
1443+ real (wp),intent (inout ) :: a(n)
1444+
1445+ integer :: i , ii , imax , j , jmax , ki , l , ll
1446+ real (wp) :: s
1447+
1448+ integer ,dimension (10 ),parameter :: k = [1 , 4 , 13 , 40 , 121 , 364 , &
1449+ 1093 , 3280 , 9841 , 29524 ]
1450+
1451+ ! selection of the increments k(i) = (3**i-1)/2
1452+ if ( n< 2 ) return
1453+ imax = 1
1454+ do i = 3 , 10
1455+ if ( n<= k(i) ) exit
1456+ imax = imax + 1
1457+ enddo
1458+
1459+ ! stepping through the increments k(imax),...,k(1)
1460+ i = imax
1461+ do ii = 1 , imax
1462+ ki = k(i)
1463+ ! sorting elements that are ki positions apart
1464+ ! so that abs(a(j)) <= abs(a(j+ki))
1465+ jmax = n - ki
1466+ do j = 1 , jmax
1467+ l = j
1468+ ll = j + ki
1469+ s = a(ll)
1470+ do while ( abs (s)<abs (a(l)) )
1471+ a(ll) = a(l)
1472+ ll = l
1473+ l = l - ki
1474+ if ( l<= 0 ) exit
1475+ enddo
1476+ a(ll) = s
1477+ enddo
1478+ i = i - 1
1479+ enddo
1480+
1481+ end subroutine daord
1482+ ! *****************************************************************************************
1483+
1484+ ! *****************************************************************************************
1485+ ! >
1486+ ! `w = sqrt(z)` for the double precision complex number `z`
1487+ !
1488+ ! z and w are interpreted as double precision complex numbers.
1489+ ! it is assumed that z(1) and z(2) are the real and imaginary
1490+ ! parts of the complex number z, and that w(1) and w(2) are
1491+ ! the real and imaginary parts of w.
1492+
1493+ subroutine dcsqrt (z ,w )
1494+
1495+ real (wp),intent (in ) :: z(2 )
1496+ real (wp),intent (out ) :: w(2 )
1497+
1498+ real (wp) :: x , y , r
1499+
1500+ x = z(1 )
1501+ y = z(2 )
1502+ if ( x< 0 ) then
1503+ if ( y/= 0.0_wp ) then
1504+ r = dcpabs(x,y)
1505+ w(2 ) = sqrt (0.5_wp * (r- x))
1506+ w(2 ) = sign (w(2 ),y)
1507+ w(1 ) = 0.5_wp * y/ w(2 )
1508+ else
1509+ w(1 ) = 0.0_wp
1510+ w(2 ) = sqrt (abs (x))
1511+ endif
1512+ elseif ( x== 0.0_wp ) then
1513+ if ( y/= 0.0_wp ) then
1514+ w(1 ) = sqrt (0.5_wp * abs (y))
1515+ w(2 ) = sign (w(1 ),y)
1516+ else
1517+ w(1 ) = 0.0_wp
1518+ w(2 ) = 0.0_wp
1519+ endif
1520+ elseif ( y/= 0.0_wp ) then
1521+ r = dcpabs(x,y)
1522+ w(1 ) = sqrt (0.5_wp * (r+ x))
1523+ w(2 ) = 0.5_wp * y/ w(1 )
1524+ else
1525+ w(1 ) = sqrt (x)
1526+ w(2 ) = 0.0_wp
1527+ endif
1528+
1529+ end subroutine dcsqrt
1530+ ! *****************************************************************************************
1531+
1532+ ! *****************************************************************************************
1533+ ! >
1534+ ! evaluation of `sqrt(x*x + y*y)`
1535+
1536+ real(wp) function dcpabs (x ,y )
1537+
1538+ real (wp),intent (in ) :: x , y
1539+ real (wp) :: a
1540+
1541+ if ( abs (x)>abs (y) ) then
1542+ a = y/ x
1543+ dcpabs = abs (x)* sqrt (1.0_wp + a* a)
1544+ elseif ( y== 0.0_wp ) then
1545+ dcpabs = 0.0_wp
1546+ else
1547+ a = x/ y
1548+ dcpabs = abs (y)* sqrt (1.0_wp + a* a)
1549+ end if
1550+
1551+ end function dcpabs
1552+ ! *****************************************************************************************
1553+
12571554! *****************************************************************************************
12581555! >
12591556! Solve the real coefficient algebraic equation by the qr-method.
0 commit comments