(1)*x30+(-465)*x29+(103385)*x28+(-14631225)*x27+(1480321269)*x26+(-114009431445)*x25 |
+(6949189247325)*x24+(-344092707928125)*x23+(14097793282984515)*x22+(-484338676679532675)*x21+(14090257524223082475)*x20+(-349600545868057540875)*x19 |
+(7435941626111727234855)*x18+(-136055808711963322871175)*x17+(2145883249334501452139775)*x16+(-29197210605623737977801375)*x15+(342563613932937660652700640)*x14+(-3460266110493898677911394000)*x13 |
+(30006513636556697864066736800)*x12+(-222457423246962063058403076000)*x11+(1401937624086807501691142239744)*x10+(-7454161471690660700139655157760)*x9+(33114629767614997850763390570240)*x8+(-121365366674745136523074652102400)*x7 |
+(360930788158836812805614538878976)*x6+(-851899888505423112503184251412480)*x5+(1547794975254719737111781253120000)*x4+(-2070792202024594683660866641920000)*x3+(1902893785240928209998216560640000)*x2+(-1059681761389533859949327155200000)*x |
+(265252859812191058636308480000000)
|
Clock c; c.start();
Vect r =Solve(q, Aberth());
cout<<"Roots:"<<endl;
for (int i = 0; i < q.degree(); i++) cout<<"#"<<i+1<<": "<<r[i]<<endl;
}
Roots:
#1: (0.1e1, -0.25877017821792895931348326448096581026e-61)
#2: (0.19999999999999999999999999999999999984e1, -0.46556680990471469891214099942031669987e-76)
#3: (0.40000000000000000000000000000000364749e1, -0.20535888801067914054504324258151119759e-62)
#4: (0.29999999999999999999999999999999998682e1, -0.1690014420565147123865015402332071313e-67)
#5: (0.60000000000000000000000000010308179885e1, -0.17069344456114038582494063531601900797e-55)
#6: (0.49999999999999999999999999999761733257e1, 0.56117336544939643771944799678521116096e-47)
#7: (0.99999999999999999999999784826963231212e1, 0.1677037890900643849669321014094637549e-45)
#8: (0.90000000000000000000000032519985952991e1, -0.10509095875125750363385727455212235666e-47)
#9: (0.14000000000000000000008402553702753828e2, 0.2015435089101158787266077152350015994e-45)
#10: (0.69999999999999999999999999991601077172e1, 0.25390980354637881208074621189882365307e-37)
#11: (0.10999999999999999999999885325082034558e2, -0.57235100952987539063160947223702612529e-40)
#12: (0.79999999999999999999999999431433217699e1, -0.19467375500487617082017239633722323927e-41)
#13: (0.12999999999999999999996347819253591034e2, 0.36353917880566144751326965843923149935e-48)
#14: (0.12000000000000000000000970795413911516e2, 0.10465433766150597832348156110497136095e-28)
#15: (0.16000000000000000000121692969865195616e2, 0.61282400956055226193665133857607039139e-44)
#16: (0.16999999999999999999732193650094651459e2, 0.2309095887500468055812263958690829855e-38)
#17: (0.17999999999999999999682383096594987337e2, 0.16812616094710630162783072442274842416e-30)
#18: (0.15000000000000000000002189951417373643e2, -0.7490939520500240247661306054365703158e-32)
#19: (0.19999999999999999999296586876141711257e2, 0.85176035248872305472653559861172840824e-31)
#20: (0.18999999999999999999529788281178441923e2, 0.53282144207137213154959172264956273312e-40)
#21: (0.21999999999999999999297348006978163749e2, 0.36943424133849245652733336879058978001e-37)
#22: (0.22999999999999999999287914975831207769e2, 0.29732741191732769710887783935183503301e-41)
#23: (0.25999999999999999999832045321006631775e2, 0.20580343010841541263617393462696565414e-34)
#24: (0.20999999999999999998631601379682898985e2, 0.85416495423790731130368144063784408372e-38)
#25: (0.28999999999999999999999511858249512079e2, 0.58775478356019121465377999997238523646e-29)
#26: (0.25000000000000000000182522016583431122e2, 0.1702818085845692419455710925989157286e-36)
#27: (0.2800000000000000000001097792243810599e2, -0.27922288574837944256539061438507685528e-31)
#28: (0.24000000000000000000512743725846821381e2, -0.18359428755560974665678223574819808583e-30)
#29: (0.27000000000000000000036044721387544108e2, 0.49609681736270557227520758047099445496e-31)
#30: (0.29999999999999999999999913709517042125e2, 0.82974904262406279750260379614458531495e-31)
2 Sebastio a Sylva method
The Sebastiao e Silva method ([Card95]) is an iterative process
for computing a selected approximate root of a polynomial p. It is
essentially the same as the power method of matrices, but it is
accelerated: instead of computing the successive powers fn, we
compute the successive squares f2n.
An iterative process based on the Sebastiao e Silva
method
- Choose a starting value f of A.
- Iterate fn+1 = (fn)2/ ||(fn)2)|| in A.
If there exists a simple root z maximizing |f|, we obtain
limn-> infty fn+1=ez.
Here, we have choosen the euclidian norm for the vectors. The process stops
if the error between two iteration is less than a value e,
fixed in advance.
Moreover, if the process is written in the Horner basis, an additionnal
interest is to have a simple way to select the root which is the nearest to a
given point, as illustred below.
Let us assume that, for a given point t
in K, there is only one simple root z closest to t. We start
the algorithm from the vector ft = (1,t,t2,..., td-1), that
is the coefficient vector in the Horner basis of p(x) -
p(t)/ (x-t)p'(t).
We have ft(z) = -p(t)/ z-t for all the roots of p,
so that the evaluation of ft at the roots of p is maximal when
|z-t| is minimal. If we want the smallest root of p, we start
the process from f0. If we want the largest we should reverse p and
look for its smallest root (see [Card95]).
If we want to obtain other roots after computing a first root z, we
apply a ``deflation'' of the polynomial p. There are two different
deflation processes, the first one is the most natural; it is called the
explicit deflation, and consists in computing explicitly
p(x)/ x-z. The second deflation process, called implicit
deflation, is as follows. One root
z is computed with a starting value f0, and the method produced a
first idempotent ez. To get a second root, we choose any g of
A (possibly f again) and start the method from the initial value
(g-gez). Since (g-g ez)(z) = 0, z is no
longer dominant, and the process cannot converge again to ez. Thus
we will obtain another idempotent ez' where
z' is the dominant root associated to g, z will be ignored. For
the next step, we choose h (possibly f or g) and start the method from
the initial value h-h(ez+ez'). Continuing in this way, we
will ultimately collect as many roots of p as desired (for more details see
[Card95]).
For this work we have choosen the implicit deflation.
2.1 Implementation
struct Sebastiao Class which gives the parameters of the Sebastiao method:
nbroot number of roots that should be computed,
nbiter maximal number of iterations allowed,
epsilon tolerance to stop the iteration.
{
int nbroot; //number of roots.
unsigned nbiter; //number of iterations.
double epsilon; //tolerance.
Sebastiao():nbroot(1),nbiter(40),epsilon(Tolerance){}
Sebastiao(const Sebastiao & m):
nbroot(m.nbroot),nbiter(m.nbiter),epsilon(m.epsilon){}
Sebastiao(int n):
nbroot(n),nbiter(40),epsilon(Tolerance) {}
Sebastiao(int n, unsigned nit):
nbroot(n),nbiter(nit),epsilon(Tolerance) {}
Sebastiao(int n, unsigned nit, double eps):
nbroot(n),nbiter(nit),epsilon(eps) {}
};
template < class R> inline
VAL< UPolyQuot< R> *> StartingValue(UPolyDense< R> p,
const typename R::value_type x0)
Returns B1,p(x,x0) in the dual basis. Used to get a starting value
of the iterative process.
template< class R>
VAL< UPolyQuot< R> *> IterFrom(const UPolyQuot< R> & p0, Sebastiao mth)
Apply Sebastiao e Silva iteration from the starting polynomial p0.
It stops either if the norm of the distance between two iterations
is smaller than mth.epsilon, or if the number of iterations goes
up to mth.nbiter.
template < class R> inline
typename R::value_type SolveOne(UPolyDense< R> & p,
const typename R::value_type & x0, Sebastiao mth)
Compute the root of the polynomial p which is the closest (in modulus)
to x0, using Sebastiao e Silva method. If there are two roots closest
to x0, the sequence will have two accumulation points and the output
solution will not be correct. This is not detected for the moment.
template < class R> inline
typename R::value_type* Solve(UPolyDense< R> & p,
const typename R::value_type & x0, Sebastiao mth)
Compute k=mth.nbroot roots of the polynomial p, using Sebastiao
e Silva method. It starts with the root the closest to x0.
If k=-1, all the roots of p are computed.
2.2 Tests:
Here are some results of experimentation for the Sebastiao e Silva
method. Some polynomials with random coefficients real and complex have been
generated, and we applied the method for the computation of one root for a
degree of 10000 and 100000. We have also computed all the root for a
polynomial with
random complex coefficients of degree 10000. One can observe that, for a
polynomial p with random coefficients, as its degree increases, the roots
of p will come closer and closer to the unit circle of the complex plane.
One root has also been computed for some univariate polynomials called truncated exponential, and this for different degrees. These polynomials
are of the form:
See the examples supplied by D.A. Bini in the
FRISCO test suite [PolTS].
- The polynomial is obtained by truncating the series of ex.
-
The roots of this polynomial are located along a curve. To have a chance to
obtain a correct result for a degree > 20, it is necessary to use a multiple
precision library. Here it is the class Scl<MPF> based on
GNU MP ([GMP]).
In the following table, we present the results for
- Polynomials with real random coefficients, of degrees 10000 and 100000.
- Polynomials with complex random coefficients, of degrees 10000, 100000
and 1000000.
- Exponential polynomials Sixi/ i!, for
some degrees of 100, 150, 200.
|
d |
x0 |
k |
T |
double |
10000 |
0.0 |
8 |
22.03s |
double |
100000 |
0.0 |
8 |
346.52s |
complex |
10000 |
(0.4,0.6) |
6 |
16.86s |
complex |
100000 |
(0.4,0.6) |
6 |
292.02s |
complex |
1000000 |
(0.4,0.6) |
7 |
2520s |
exp |
100 |
(0.0,0.8) |
6 |
45s |
exp |
150 |
(0.0,0.8) |
6 |
59s |
exp |
200 |
(0.0,0.8) |
6 |
101s |
where d is the degree of the polynomial, x0 the starting value for the
iterative process, k is the number of iterations to compute one root and
T is the total time of the computation. These experimentations have been
performed on a Dec workstation with 496M of local memory.
3 Exclusion methodsThe methods of this family are based on a test which answers
- No root in the interval.
- I don't know.
If we are in the first case, we remove the interval. Otherwise, the
interval is splitted into two subintervals, to which we apply the test
recursively.
The test implemented below use the function
where f is a polynomial of degree d. We can check that
if Df(x0,r)³ 0, the interval
[x0-r,x0+r] does not contain a root of f.
template< class R>
typename R::value_type Exclude(const R & p,
const typename R::value_type & x0,
const typename R::value_type & r)
Test if the box B(x0,r) does not contain a (real) root.
If the result is positive, this is the case. Otherwise, we cannot say.
p is a univariate polynomial, x0 is the center of the box, and r
its radius
template< class POL, class C>
VAL< vector< C> *> Locate(const POL& p,const C& a,const C& b,const C & epsilon)
Output a sequence of points, such that the real roots
of the univariate polynomial p in the interval [a,b], are at a distance
less than epsilon, from one of these points.
template< class POL, class C> inline
VAL< vector< C> *> Locate(const POL& p, const box< C> & b, const C & epsilon)
The same but with a box b.
|