1 /*******************************************************************************
2 
3 "A Collection of Useful C++ Classes for Digital Signal Processing"
4  By Vinnie Falco
5 
6 Official project location:
7 https://github.com/vinniefalco/DSPFilters
8 
9 See Documentation.cpp for contact information, notes, and bibliography.
10 
11 --------------------------------------------------------------------------------
12 
13 License: MIT License (http://www.opensource.org/licenses/mit-license.php)
14 Copyright (c) 2009 by Vinnie Falco
15 
16 Permission is hereby granted, free of charge, to any person obtaining a copy
17 of this software and associated documentation files (the "Software"), to deal
18 in the Software without restriction, including without limitation the rights
19 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20 copies of the Software, and to permit persons to whom the Software is
21 furnished to do so, subject to the following conditions:
22 
23 The above copyright notice and this permission notice shall be included in
24 all copies or substantial portions of the Software.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 THE SOFTWARE.
33 
34 *******************************************************************************/
35 
36 #include "DspFilters/Common.h"
37 #include "DspFilters/RootFinder.h"
38 #include <stdexcept>
39 
40 namespace Dsp {
41 
solve(int degree,bool polish,bool doSort)42 void RootFinderBase::solve (int degree,
43                             bool polish,
44                             bool doSort)
45 {
46   assert (degree <= m_maxdegree);
47 
48   const double EPS = 1.0e-30;
49 
50   int its;
51   complex_t x, b, c;
52 
53   int m = degree;
54 
55   // copy coefficients
56   for (int j = 0; j <= m; ++j)
57     m_ad[j] = m_a[j];
58 
59   // for each root
60   for (int j = m - 1; j >= 0; --j)
61   {
62     // initial guess at 0
63     x = 0.0;
64     laguerre (j + 1, m_ad, x, its);
65 
66     if (fabs (std::imag(x)) <= 2.0 * EPS * fabs (std::real(x)))
67       x = complex_t (std::real(x), 0.0);
68 
69     m_root[j] = x;
70 
71     // deflate
72     b = m_ad[j+1];
73     for (int jj = j; jj >= 0; --jj)
74     {
75       c = m_ad[jj];
76       m_ad[jj] = b;
77       b = x * b + c;
78     }
79   }
80 
81   if (polish)
82     for (int j = 0; j < m; ++j)
83       laguerre (degree, m_a, m_root[j], its);
84 
85   if (doSort)
86     sort (degree);
87 }
88 
sort(int degree)89 void RootFinderBase::sort (int degree)
90 {
91   for (int j = 1; j < degree; ++j)
92   {
93     complex_t x = m_root[j];
94 
95     int i;
96     for (i = j - 1; i >= 0; --i )
97     {
98       if (m_root[i].imag() >= x.imag())
99         break;
100 
101       m_root[i+1] = m_root[i];
102     }
103 
104     m_root[i+1] = x;
105   }
106 }
107 
108 //------------------------------------------------------------------------------
109 
laguerre(int degree,complex_t a[],complex_t & x,int & its)110 void RootFinderBase::laguerre (int degree,
111                            complex_t a[],
112                            complex_t& x,
113                            int& its)
114 {
115   const int MR = 8, MT = 10, MAXIT = MT * MR;
116   const double EPS = std::numeric_limits<double>::epsilon();
117 
118   static const double frac[MR + 1] =
119     {0.0, 0.5, 0.25, 0.75, 0.13, 0.38, 0.62, 0.88, 1.0};
120 
121   complex_t dx, x1, b, d, f, g, h, sq, gp, gm, g2;
122 
123   int m = degree;
124   for (int iter = 1; iter <= MAXIT; ++iter)
125   {
126     its = iter;
127     b = a[m];
128     double err = std::abs(b);
129     d = f = 0.0;
130     double abx = std::abs(x);
131     for (int j = m - 1; j >= 0; --j)
132     {
133       f = x * f + d;
134       d = x * d + b;
135       b = x * b + a[j];
136       err = std::abs(b) + abx * err;
137     }
138     err *= EPS;
139     if (std::abs(b) <= err)
140       return;
141     g  = d / b;
142     g2 = g * g;
143     h  = g2 - 2.0 * f / b;
144 
145     sq = sqrt (double(m - 1) * (double(m) * h - g2));
146     gp = g + sq;
147     gm = g - sq;
148 
149     double abp = std::abs (gp);
150     double abm = std::abs (gm);
151     if (abp < abm)
152       gp = gm;
153     dx = std::max(abp, abm) > 0.0 ? double(m) / gp : std::polar (1 + abx, double(iter));
154     x1 = x - dx;
155     if (x == x1)
156       return;
157     if (iter % MT != 0)
158       x = x1;
159     else
160       x -= frac[iter / MT] * dx;
161   }
162 
163   throw std::logic_error ("laguerre failed");
164 }
165 
166 //------------------------------------------------------------------------------
167 
eval(int degree,const complex_t & x)168 complex_t RootFinderBase::eval (int degree,
169                             const complex_t& x )
170 {
171   complex_t y;
172 
173   if (x != 0.)
174   {
175     for (int i = 0; i <= degree; ++i)
176       y += m_a[i] * pow (x, double(i));
177   }
178   else
179   {
180     y = m_a[0];
181   }
182 
183   return y;
184 }
185 
186 
187 }
188