Low-Degree Polynomial Roots
David Eberly
Geometric Tools, LLC
http://www.geometrictools.com/
c 1998-2016. All Rights Reserved.
Copyright Created: July 15, 1999
Last Modified: April 4, 2015
Contents
1 Introduction
2
2 Discriminants
2
3 Preprocessing the Polynomials
4
4 Quadratic Polynomials
5
4.1
A Floating-Point Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
4.2
A Mixed-Type Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
5 Cubic Polynomials
7
5.1
Real Roots of Multiplicity Larger Than One . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
5.2
One Simple Real Root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
5.3
Three Simple Real Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
5.4
A Mixed-Type Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
6 Quartic Polynomials
11
6.1
Processing the Root Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
6.2
The Biquadratic Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
6.3
Multiplicity Vector (3, 1, 0, 0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
6.4
Multiplicity Vector (2, 2, 0, 0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
6.5
Multiplicity Vector (2, 1, 1, 0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
6.6
Multiplicity Vector (1, 1, 1, 1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
6.7
A Mixed-Type Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1
1
Introduction
Consider a polynomial of degree d of the form
p(y) =
d
X
pi y i
(1)
i=0
where the pi are real numbers and where pd 6= 0. A root of the polynomial is a number r, real or non-real
(complex-valued with nonzero imaginary part) such that p(r) = 0. The polynomial can be factored as
p(y) = (y − r)m f (y), where m is a positive integer and f (r) 6= 0. The power m is the multiplicity of the
root. If m = 1, the root is said to be a simple root. If m ≥ 2, the root is said to be a multiple root. The
fundamental theorem of algebra states that p(y) has exactly d roots, counting the multiplicities. If the K
PK−1
distinct roots are yk for 0 ≤ k < K and if mk is the multiplicity of root yk , then d = k=0 mk . We are
assuming that the pi are real numbers, so if a root is non-real, say, r = u + ıv, where v 6= 0, then r̄ = u − ıv
is also a root. The pair (r, r̄) is referred to as a complex conjugate pair of roots.
The roots of polynomials of degrees 2, 3, or 4 can be written using closed-form algebraic expressions. The
theory of polynomials shows us that there cannot be general closed-form algebraic expressions for the roots
of p(y) for d ≥ 5. In practice, numerical root finders must be used to locate the roots. For degrees 2, 3, and
4, one may compute the roots using the closed-form expressions, but this approach is typically ill conditioned
when using floating-point arithmetic. The main problem occurs in sign tests used to classify the roots, both
in domain (real or non-real) and in multiplicity (determine m).
This document provides a robust approach for computing the roots using the closed-form expressions. The
assumption is that the polynomial coefficients are floating-point numbers. In an implementation, they are
converted to exact rational representations so that the root classification is performed with exact rational
arithmetic and the result is theoretically correct. Naturally, the coefficients themselves might have been
computed in a manner that introduced floating-point rounding errors. The discussion here does not take the
coefficient errors into account, because only you the programmer have—and can take advantage of—that
knowledge.
2
Discriminants
The first step in classification uses a concept called the discriminant of a polynomial p(y) and is defined as
Y
Y
∆ = p2d−2
(ri − rj )2 = (−1)d(d−1)/2 pd2d−2 (ri − rj )
(2)
d
i<j
i6=j
where r0 through rd−1 are the roots of p(y) counting the multiplicities: a root r with multiplicity m occurs
m times in the set {r0 , . . . , rd−1 }. In the event a root exists with multiplicity 2 or larger, it is clear that
∆ = 0; thus, at its highest level the discriminant lets you know whether or not a polynomial has repeated
roots. More information is actually known regarding the sign of ∆,
• ∆ > 0: for some integer k with 0 ≤ k ≤ d/4, there are 2k distinct complex-conjugate pairs of roots
and d − 4k distinct real roots. Each root has a multiplicity of 1.
• ∆ < 0: for some integer k with 0 ≤ k ≤ (d − 2)/4, there are 2k + 1 distinct complex-conjugate pairs
of roots and d − 4k − 2 distinct real roots. Each root has a multiplicity of 1.
2
• ∆ = 0: at least one root r has multiplicity m ≥ 2 and r may be either real or non-real. If r is non-real,
then its conjugate r̄ also has multiplicity m.
The prototypical case is p(y) = p0 + p1 y + p2 y 2 . The discriminant is ∆ = p21 − 4p0 p2 . If ∆ > 0, the square
root is a positive real number and there are two distinct real roots,
√
√
−p1 − ∆
−p1 + ∆
r0 =
, r1 =
2p2
2p2
The integer k in the sign tests is 0, so we have 2 distinct real roots and 0 distinct complex-conjugate pairs
of roots. If ∆ < 0, the square root is a pure imaginary number and the roots are non-real,
√
√
−p1 − ı −∆
−p1 + ı −∆
r0 =
, r1 =
2p2
2p2
The integer k in the sign tests is 0. If ∆ = 0, we have a repeated real root,
r0 = r1 =
−p1
2p2
so its multiplicity is m = 2.
Of course we usually do not know the roots of p(y), so Equation (2) is not immediately helpful. However, the
discriminant is related to another concept called the resultant of two polynomials, whichP
is the product of
d−1
the differences between the roots of the polynomials. The first derivative of p(y) is p0 (y) = i=0 (i + 1)pi+1 y i
0
0
and the resultant of p(y) and p (y) is denoted R(p, p ). It is the determinant of a (2d − 1) × (2d − 1) matrix
called the Sylvester matrix,
0
R(p, p ) = det
pd
pd−1
pd−2
...
p1
p0
0...
...
0
0
.
.
.
pd
pd−1
pd−2
...
p1
p0
0...
0
.
.
.
0
...
0
pd
pd−1
pd−2
...
p1
p0
dpd
(d − 1)pd−1
(d − 2)pd−2
...
p1
0
...
...
0
0
.
.
.
dpd
(d − 1)pd−1
(d − 2)pd−2
...
p1
0
...
0
.
.
.
0
0
...
0
dpd
(d − 1)pd−1
(d − 2)pd−2
...
p1
(3)
The discriminant is then
∆ = (−1)d(d−1)/2 R(p, p0 )/pd
The discriminant for the degree-2 (quadratic) polynomial is
p
p1
2
−1
∆ = p2 det 2p2 p1
0 2p2
= p21 − 4p0 p2
3
p0
(4)
0
p1
(5)
The discriminant for the degree-3 (cubic) polynomial is
p
p2
p1
3
0
p3
p2
−1
∆ = p3 det 3p3 2p2 p1
0 3p3 2p2
0
0 3p3
=
p1
0
p1
2p2
0
p0
0
0
p1
(6)
−27p20 p23 + 18p0 p1 p2 p3 − 4p0 p32 − 4p31 p3 + p21 p22
The discriminant for the degree-4 (quartic)
p
p3
p2
p1
4
0
p4
p3
p2
0
0
p4
p3
1
∆ = p4 det 4p4 3p3 2p2 p1
0 4p4 3p3 2p2
0
0 4p4 3p3
0
0
0 4p4
=
p0
polynomial is
p0
0
0
p1
p0
0
p2
p1
p0
0
0
0
p1
0
0
2p2
p1
0
3p3
2p2
p1
(7)
256p30 p34 − 192p20 p1 p3 p24 − 128p20 p22 p24 + 144p20 p2 p23 p4 − 27p20 p43 + 144p0 p21 p2 p24 − 6p0 p21 p23 p4
− 80p0 p1 p22 p3 p4 + 18p0 p1 p2 p33 + 16p0 p42 p4 − 4p0 p32 p23 − 27p41 p24 + 18p31 p2 p3 p4 − 4p31 p33
− 4p21 p32 p4 + p21 p22 p23
For larger d, the discriminant expressions become quite complicated. These occur in a simpler format for
preprocessed polynomials.
3
Preprocessing the Polynomials
Preprocessing steps may be applied that make the root classification and construction simpler. The steps
are error free when performed with exact rational arithmetic. In the analysis of p(y), the polynomial is made
monic by dividing through by its leading coefficient to obtain
q(y) =
d−1
X
qi y i + y d
(8)
i=0
where qi = pi /pd for 0 ≤ i ≤ d−1. The polynomials p(y) and q(y) have the same set of roots and multiplicities.
The monic polynomial is made depressed by eliminating the y d−1 term using a simple translation, y =
4
x − qd−1 /d, to obtain
c(x) =
d−2
X
ci xi + xd
(9)
i=0
The coefficients ci are obtained from binomial expansions of powers of (x − qd−1 /d). These will be listed for
each low-degree polynomial discussed in later sections. It is possible that low-order coefficients of c(x) are
zero, so the analysis must allow for this. The roots of c(x) of Equation (9) are computed and then inverse
transformed to obtain roots to p(y). Specifically, if x̂ is a root of c(x), the corresponding root of p(y) is
ŷ = x̂ − qd−1 /d.
An important observation about depressed polynomials helps us construct roots. The depressed polynomial
c(x) with roots r0 through rd−1 (counting multiplicities) factors as
c(x) =
d−1
Y
(x − ri )
(10)
i=0
The coefficients ci are related to sums of products of roots. These
formulas are referred to as the elementary
Pd−1
symmetric polynomials of the roots. In particular, cd−1 = − i=0 ri , which is the negation of the sum of
Qd−1
the roots, and c0 = i=0 ri , which is the product of the roots. The depressed polynomial has the constraint
that cd−1 = 0, so the roots of the original polynomial p(y) have been translated by the change of variables
y = x − qd−1 /d so that the sum of the roots of c(x) is zero.
4
Quadratic Polynomials
The quadratic polynomial of interest is p(y) = p2 y 2 + p1 y + p0 , where p2 6= 0. The monic polynomial is
q(y) = y 2 +q1 y+q0 , where q1 = p1 /p2 and q0 = p0 /p2 . The depressed polynomial is obtained by transforming
y = x − q1 /2 to obtain c(x) = x2 + c0 , where c0 = q0 − q12 /4. The discriminant for c(x) is obtained from
Equation (5) by substituting p0 = c0 , p1 = 0, and p2 = 1,
∆ = −4c0
(11)
√
If ∆ > 0, c(x) has two simple real-valued roots, r = ± −c0 . If ∆ < 0, c(x) has a complex-conjugate pair of
√
roots, r = ±ı c0 . If ∆ = 0, c(x) has a real root r = 0 of multiplicity 2.
4.1
A Floating-Point Implementation
The straightforward code for computing the real-valued roots is shown next, where Real refers to a floatingpoint type such as float or double. The map stores pairs (r, m), where r is a real-valued root and m is its
multiplicity. The precondition is that p2 6= 0.
v o i d S o l v e Q u a d r a t i c ( R e a l p0 , R e a l p1 , R e a l p2 , map<R e a l , i n t >& rmMap )
{
R e a l q0 = p0 / p2 ;
// p o t e n t i a l r o u n d i n g e r r o r
R e a l q1 = p1 / p2 ;
// p o t e n t i a l r o u n d i n g e r r o r
R e a l q 1 h a l f = q1 / 2 ; // p o t e n t i a l r o u n d i n g e r r o r
R e a l c0 = q0 − q 1 h a l f ∗ q 1 h a l f ;
// p o t e n t i a l r o u n d i n g e r r o r
R e a l d e l t a = −4 ∗ c0 ;
// P o t e n t i a l
misclassification
if
theoretical
5
delta
is
nearly zero .
i f ( d e l t a > 0)
{
// Two s i m p l e r o o t s .
Real r1 = s q r t ( d e l t a ) ;
// u s u a l l y i n e x a c t r e s u l t
R e a l r 0 = −r 1 ;
rmMap . i n s e r t ( r 0 − q 1 h a l f , 1 ) ;
// p o t e n t i a l r o u n d i n g e r r o r
rmMap . i n s e r t ( r 1 − q 1 h a l f , 1 ) ;
// p o t e n t i a l r o u n d i n g e r r o r
}
e l s e i f ( d e l t a == 0 )
{
// One d o u b l e r o o t .
Real r0 = 0;
rmMap . i n s e r t ( r 0 − q 1 h a l f , 2 ) ;
}
else
// d e l t a < 0
{
// A c o m p l e x c o n j u g a t e p a i r o f r o o t s .
// Complex z0 = −q1 /2 − i ∗ s q r t (− d e l t a ) ;
// Complex z1 = −q1 /2 + i ∗ s q r t (− d e l t a ) ;
}
}
The comments indicate the places where floating-point rounding errors can occur. As you can see, nearly
every line of code has potential problems. The main problem is the misclassification of the roots when the
sign of ∆ is not computed exactly. Even when the quadratic formula is used directly for p(y), where the
discriminant is ∆ = p21 − 4p0 p2 , you still have potential misclassification when ∆ is nearly zero and the
floating-point errors lead to a theoretically incorrect sign.
4.2
A Mixed-Type Implementation
For rational p0 , p1 , and p2 , we can use exact rational arithmetic to compute q0 , q1 , c0 , and ∆ without errors.
The classification of roots using ∆ is therefore theoretically correct, so the following listing is more robust
than the floating-point-only version. The code for computing the roots of the depressed quadratic is factored
into a separate function, allowing it to be shared by the cubic root finder.
v o i d S o l v e Q u a d r a t i c ( R e a l f p 0 , R e a l f p 1 , R e a l f p 2 , map<R e a l , i n t >& rmMap )
{
R a t i o n a l p0 = f p 0 , p1 = f p 1 , p2 = f p 2 ;
// c o n v e r s i o n s t o r a t i o n a l s , no e r r o r
R a t i o n a l q0 = p0 / p2 ;
// no e r r o r
R a t i o n a l q1 = p1 / p2 ;
// no e r r o r
R a t i o n a l q 1 h a l f = q1 / 2 ; // no e r r o r
R a t i o n a l c0 = q0 − q 1 h a l f ∗ q 1 h a l f ;
// no e r r o r
map<R a t i o n a l , i n t > rmLocalMap ;
S o l v e D e p r e s s e d Q u a d r a t i c ( c0 , rmLocalMap ) ;
f o r e a c h ( rm i n rmLocalMap )
{
// The c o n v e r s i o n from R a t i o n a l t o R e a l h a s p o t e n t i a l r o u n d i n g e r r o r s .
R a t i o n a l r o o t = rm . f i r s t − q 1 h a l f ;
rmMap . i n s e r t ( ( R e a l ) r o o t , rm . s e c o n d ) ;
}
}
v o i d S o l v e D e p r e s s e d Q u a d r a t i c ( R a t i o n a l c0 , map<R a t i o n a l , i n t >& rmMap )
{
i f ( c0 < 0 ) // d e l t a > 0
{
// Two s i m p l e r o o t s .
R a t i o n a l r 1 = ( R a t i o n a l ) s q r t (−( d o u b l e ) c0 ) ;
// p o t e n t i a l r o u n d i n g e r r o r s
R a t i o n a l r 0 = −r 1 ;
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
}
6
else
{
i f ( c0 == 0 )
// d e l t a = 0
// One d o u b l e r o o t ( r 0 = 0 ) .
rmMap . i n s e r t ( 0 , 2 ) ;
}
else
{
// d e l t a < 0
// A c o m p l e x c o n j u g a t e p a i r o f r o o t s .
// Complex z0 = −q1 /2 − i ∗ s q r t ( c0 ) ;
// Complex z1 = −q1 /2 + i ∗ s q r t ( c0 ) ;
}
}
The root approximations can be improved by implementing an approximation to the sqrt function using
only rational arithmetic and producing an output with enough precision so that the roots are correctly
rounded for the precision supplied by Real. In this sense, SolveQuadratic would conform to the IEEE 7542008 requirements of correct rounding that it imposes on the standard mathematics functions commonly
supported on floating-point hardware.
5
Cubic Polynomials
The cubic polynomial of interest is p(y) = p3 y 3 + p2 y 2 + p1 y + p0 , where p3 6= 0. The monic polynomial is
q(y) = y 3 + q2 y 2 + q1 y + q0 , where q2 = p2 /p3 , q1 = p1 /p3 and q0 = p0 /p3 . The depressed polynomial is
obtained by transforming y = x − q2 /3 to obtain c(x) = x3 + c1 x + c0 , where c0 = q0 − q1 q2 /3 + 2q23 /27 and
c1 = q1 − q22 /3. The discriminant for c(x) is obtained from Equation (6) by substituting p0 = c0 , p1 = c1 ,
p2 = 0, and p3 = 1,
∆ = −(4c31 + 27c20 )
(12)
According to the high-level sign tests for the discriminant, if ∆ > 0, there are three simple real roots. If
∆ < 0, there is a simple real root and a complex conjugate pair of roots. If ∆ = 0, there must be a root
of multiplicity at least 2. Because non-real roots occur only as complex conjugate pairs, this forces either a
single real root of multiplicity 3 or two distinct real roots, one with multiplicity 1 and one with multiplicity
2. A more detailed analysis is required in order to implement an algorithm.
5.1
Real Roots of Multiplicity Larger Than One
Real roots of multiplicity larger than 1 are easily constructed by examining the derivatives of c(x). The first
derivative is c0 (x) = 3x2 + c1 and the second derivative is c00 (x) = 6x.
A real root of multiplicity 3 must be a solution to c(x) = 0, c0 (x) = 0, and c00 (x) = 0. This forces x = 0,
c1 = 0, and c0 = 0; that is, c(x) = x3 .
A real root of multiplicity 2 must be a solution c(x) = 0 and c0 (x) = 0 subject to c00 (x) 6= 0. The last
condition implies x 6= 0. The equation c0 (x) = 0 then requires c1 < 0, and x2 = −c1 /3. Substituting this
into c(x) = 0, we obtain 0 = c(x) = 2c1 x/3 + c0 which implies a double root r0 = −3c0 /(2c1 ) with c0 6= 0.
Let the other root be named r1 . The zero root sum condition for the depressed polynomial is 2r0 + r1 = 0,
which implies r1 = −2r0 .
7
5.2
One Simple Real Root
Consider the case of one simple real root and a complex-conjugate pair of roots. The real root can be
constructed using the following observation. A real number may be written as the sum of two real numbers,
so let the root be r0 = u + v, where u and v are to be determined. Observe that r02 = u2 + 2uv + v 2 and
r03 = u3 + 3u2 v + 3uv 2 + v 3 = 3uv(u + v) + u3 + v 3 = (3uv)r0 + (u3 + v 3 )
(13)
Because r0 is a root of c(x),
0 = r03 + c1 r0 + c0 = (3uv + c1 )r0 + (u3 + v 3 + c0 )
(14)
It is sufficient to compute u and v for which 3uv = −c1 and u3 + v 3 = −c0 . Cubing the first expression,
we have u3 v 3 = (−c1 /3)3 . Define α = u3 and β = v 3 ; then, αβ = (−c1 /3)3 and α + β = −c0 . Solving the
second equation for β and substituting in the first,
α2 + c0 α + (−c1 /3)3 = 0
(15)
This is a quadratic equation with roots
α=
−c0 −
p
−∆/27
2
, β=
−c0 +
p
−∆/27
2
(16)
where ∆ is the discriminant defined by Equation (12). We know that ∆ < 0 for the case under consideration,
so α and β are real and the (principal) cube roots are real. We conclude that
r0 = u + v = α
1/3
+β
1/3
=
−c0 −
p
−∆/27
!1/3
2
+
−c0 +
p
−∆/27
!1/3
2
(17)
The non-real roots are obtained by factoring the polynomial knowing the simple real root,
x3 + c1 x + c0 = (x − r0 )(x2 + r0 x + (r02 + c1 )) = 0
(18)
The quadratic factor has roots
p
−r0 ± ı 3r02 + 4c1
2
(19)
where 3r02 + 4c1 > 0.
To minimize operations, the case c0 6= 0 and c1 = 0 can be handled separately. The real root is simply
r0 = (−c0 )1/3 , √
where the cube root is the √
real-valued one. The non-real roots are provided by Equation (19),
r1 = r0 (−1 − ı 3)/2 and r2 = r0 (−1 + ı 3)/2.
5.3
Three Simple Real Roots
The construction in the previous section for a real root r0 = u + v still applies, but the values α and β of
Equation (16) are now non-real,
p
p
−c0 − ı ∆/27
−c0 + ı ∆/27
α=
, β=
(20)
2
2
8
where ∆ > 0. The polar representation in the complex plane of the second root is
p
β = −c0 + ı ∆/27 /2 = ρ(cos θ + ı sin θ) = ρ exp(ıθ)
(21)
where ρ is the length of β as a 2-tuple in the complex plane and θ is the counterclockwise angle formed by
β with the positive real axis of the complex plane. Specifically,
q
p
p
ρ = (−c0 /2)2 + ( ∆/27/2)2 , θ = atan2( ∆/27/2, −c0 /2)
(22)
There are three cube roots,
β 1/3 = ρ1/3 exp(ıθ/3), ρ1/3 exp(ı(θ/3 + 2π/3)), ρ1/3 exp(ı(θ/3 − 2π/3))
(23)
The cube roots of α are the complex conjugates of the cube roots of β,
α1/3 = ρ1/3 exp(−ıθ/3), ρ1/3 exp(−ı(θ/3 + 2π/3)), ρ1/3 exp(−ı(θ/3 − 2π/3))
(24)
The real-valued polynomial roots are the sums of the cube roots and their complex conjugates,
r0
r1
= ρ1/3 exp(ıθ/3) + ρ1/3 exp(−ıθ/3)
=
2ρ1/3 cos(θ/3)
=
ρ1/3 exp(ı(θ/3 + 2π/3)) + ρ1/3 exp(−ı(θ/3 + 2π/3))
2ρ1/3 cos(θ/3 + 2π/3)
√
= ρ1/3 (− cos(θ/3) − 3 sin(θ/3))
=
r2
=
ρ1/3 exp(ı(θ/3 − 2π/3)) + ρ1/3 exp(−ı(θ/3 − 2π/3))
=
2ρ1/3 cos(θ/3 − 2π/3)
√
ρ1/3 (− cos(θ/3) + 3 sin(θ/3))
=
(25)
As expected for the depressed cubic polynomial, r0 + r1 + r2 = 0.
5.4
A Mixed-Type Implementation
The straightforward floating-point implementation suffers the same problem as for the quadratic polynomial.
Floating-point rounding errors can cause a misclassification of the root domain or multiplicity. The implementation listed next uses exact rational arithmetic to provide a correct classification. The precondition
is that p3 6= 0. The code for computing the roots of the depressed quadratic is factored into a separate
function, allowing it to be shared by the quartic root finder.
v o i d S o l v e C u b i c ( R e a l f p 0 , R e a l f p 1 , R e a l f p 2 , R e a l f p 3 , map<R e a l , i n t >& rmMap )
{
R a t i o n a l p0 = f p 0 , p1 = f p 1 , p2 = f p 2 , p3 = f p 3 ;
R a t i o n a l q0 = p0 / p3 ;
R a t i o n a l q1 = p1 / p3 ;
9
Rational
Rational
Rational
Rational
q2 = p2
q2third
c0 = q0
c1 = q1
/
=
−
−
p3 ;
q2 / 3 ;
q 2 t h i r d ∗ ( q1 − 2 ∗ q 2 t h i r d ∗ q 2 t h i r d ) ;
q2 ∗ q 2 t h i r d ;
map<R a t i o n a l , i n t > rmLocalMap ;
S o l v e D e p r e s s e d C u b i c ( c0 , c1 , rmLocalMap ) ;
f o r e a c h ( rm i n rmLocalMap )
{
R a t i o n a l r o o t = rm . f i r s t − q 2 t h i r d ;
rmMap . i n s e r t ( ( R e a l ) r o o t , rm . s e c o n d ) ;
}
}
v o i d S o l v e D e p r e s s e d C u b i c ( R a t i o n a l c0 , R a t i o n a l c1 , map<R a t i o n a l , i n t >& rmMap )
{
// H a n d l e t h e s p e c i a l c a s e o f c0 = 0 , i n w h i c h c a s e t h e p o l y n o m i a l r e d u c e s
// t o a d e p r e s s e d q u a d r a t i c .
i f ( c0 == 0 )
{
S o l v e D e p r e s s e d Q u a d r a t i c ( c1 , rmMap ) ;
m a p i t e r a t o r i t e r = rmMap . f i n d ( 0 ) ;
i f ( i t e r != rmMap . end ( ) )
{
// The q u a d r a t i c h a s a r o o t o f z e r o , s o i n c r e a s e i t s m u l t i p l i c i t y .
++i t e r −>s e c o n d ;
}
else
{
// The q u a d r a t i c d o e s n o t h a v e a r o o t o f z e r o .
I n s e r t one f o r t h e c u b i c .
rmMap . i n s e r t ( 0 , 1 ) ;
}
return ;
}
// H a n d l e t h e s p e c i a l c a s e o f c0 != 0 and c1 = 0 .
i f ( c1 == 0 )
{
Rational r0 ;
i f ( c0 > 0 )
{
r 0 = ( R a t i o n a l )−pow ( ( d o u b l e ) c0 , 1 . 0 / 3 . 0 ) ;
}
else
{
r 0 = ( R a t i o n a l ) pow(−( d o u b l e ) c0 , 1 . 0 / 3 . 0 ) ;
}
rmMap . i n s e r t ( s t d : : m a k e p a i r ( r0 , 1 ) ) ;
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = r 0 ∗(−1 − i ∗ s q r t ( 3 ) ) / 2 ;
// Complex z1 = r 0 ∗(−1 + i ∗ s q r t ( 3 ) ) / 2 ;
return ;
}
// At t h i s ti me , c0 != 0 and c1 != 0 .
R a t i o n a l d e l t a = −(4 ∗ c1 ∗ c1 ∗ c1 + 27 ∗ c0 ∗ c0 ) ;
i f ( d e l t a > 0)
{
// T h r e e s i m p l e r o o t s .
Rational deltaDiv27 = delta / 27;
R a t i o n a l b e t a R e = −c0 / 2 ;
R a t i o n a l betaIm = s q r t ( ( double ) d e l t a D i v 2 7 ) / 2 ;
R a t i o n a l t h e t a = a t a n 2 ( ( d o u b l e ) betaIm , ( d o u b l e ) b e t a R e ) ;
Rational thetaDiv3 = theta / 3;
double angle = ( double ) thetaDiv3 ;
Rational cs = ( Rational ) cos ( angle ) ;
R a t i o n a l sn = ( R a t i o n a l ) s i n ( a n g l e ) ;
R a t i o n a l rhoSqr = betaRe ∗ betaRe + betaIm ∗ betaIm ;
R a t i o n a l r h oP ow Th i rd = ( R a t i o n a l ) pow ( ( d o u b l e ) r h o S q r , 1 . 0 / 6 . 0 ) ;
R a t i o n a l temp0 = rh oP ow T hi rd ∗ c s ;
10
R a t i o n a l temp1 = rh oP ow T hi rd ∗ s n ∗ ( R a t i o n a l ) s q r t ( 3 . 0 ) ;
R a t i o n a l r 0 = 2 ∗ temp0 ;
R a t i o n a l r 1 = −temp0 − temp1 ;
R a t i o n a l r 2 = −temp0 + temp1 ;
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
rmMap . i n s e r t ( r2 , 1 ) ;
}
else
{
i f ( d e l t a < 0)
// One s i m p l e r o o t .
R a t i o n a l temp0 = −c0 / 2 ;
Rational deltaDiv27 = delta / 27;
R a t i o n a l temp1 = ( R a t i o n a l ) s q r t (−( d o u b l e ) d e l t a D i v 2 7 ) / 2 ;
R a t i o n a l temp2 = temp0 − temp1 ;
R a t i o n a l temp3 = temp0 + temp1 ;
i f ( temp2 >= 0 )
{
temp2 = ( R a t i o n a l ) pow ( ( d o u b l e ) temp2 , 1 . 0 / 3 . 0 ) ;
}
else
{
temp2 = ( R a t i o n a l )−pow(−( d o u b l e ) temp2 , 1 . 0 / 3 . 0 ) ;
}
i f ( temp3 >= 0 )
{
temp3 = ( R a t i o n a l ) pow ( ( d o u b l e ) temp3 , 1 . 0 / 3 . 0 ) ;
}
else
{
temp3 = ( R a t i o n a l )−pow(−( d o u b l e ) temp3 , 1 . 0 / 3 . 0 ) ;
}
R a t i o n a l r 0 = temp2 + temp3 ;
rmMap . i n s e r t ( r0 , 1 ) ;
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = (− r 0 − i ∗ s q r t (3∗ r 0 ∗ r 0 +4∗c1 ) ) / 2 ;
// Complex z1 = (− r 0 + i ∗ s q r t (3∗ r 0 ∗ r 0 +4∗c1 ) ) / 2 ;
}
else
{
// d e l t a = 0
// One s i m p l e r o o t and one d o u b l e r o o t .
R a t i o n a l r 0 = −3 ∗ c0 / ( 2 ∗ c1 ) ;
r 1 = −2 ∗ r 0 ;
rmMap . i n s e r t ( r0 , 2 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
}
}
6
Quartic Polynomials
The quartic polynomial of interest is p(y) = p4 y 4 + p3 y 3 + p2 y 2 + p1 y + p0 , where p4 6= 0. The monic
polynomial is q(y) = y 4 + q3 y 3 + q2 y 2 + q1 y + q0 , where q3 = p3 /p4 , q2 = p2 /p4 , q1 = p1 /p4 , and q0 = p0 /p4 .
The depressed polynomial is obtained by transforming y = x − q3 /4 to obtain c(x) = x4 + c2 x2 + c1 x + c0 ,
where c0 = q0 − q3 q1 /4 + q32 q2 /16 − 3q34 /256, c1 = q1 − q3 q2 /2 + q33 /8, and c2 = q2 − 3q32 /8. The discriminant
for c(x) is obtained from Equation (7) by substituting p0 = c0 , p1 = c1 , p2 = c2 , p3 = 0, and p4 = 1,
∆ = 256c30 − 128c22 c20 + 144c2 c21 c0 − 27c41 + 16c42 c0 − 4c32 c21
(26)
Some auxiliary quantities for classification are
a0 = 12c0 + c22 , a1 = 4c0 − c22
11
(27)
The constructions of the roots in the next sections use derivatives of c(x). The first derivative is c0 (x) =
4x3 + 2c2 x + c1 , the second derivative is c00 (x) = 12x2 + 2c2 , and the third derivative is c000 (x) = 24x. Keep
in mind that any of the cases with a repeated root yield ∆ = 0.
The classification is shown in Table 1. The table is exhaustive, listing all possible combinations of root domain
and multiplicity. A real root is named ri . A non-real root is named zi and its complex conjugate z̄i is also a
non-real root. The names are for distinct roots. A multiplicity vector is used to describe the multiplicities of
the roots. A vector is of the form (m0 , m1 , m2 , m3 ) ∈ {(4, 0, 0, 0), (3, 1, 0, 0), (2, 2, 0, 0), (2, 1, 1, 0), (1, 1, 1, 1)}.
The construction is presented in later sections, each section describing a particular multiplicity vector. A
classification summary without details is found at the Wikipedia quartic function page.
Table 1. Classification of the roots for a depressed quartic polynomial.
multiplicity
(4, 0, 0, 0)
factors
(x − r0 )
4
3
discriminant
conditions
∆=0
c2 = 0 ∧ a0 = 0 ∧ a1 = 0
(3, 1, 0, 0)
(x − r0 ) (x − r1 )
∆=0
c2 < 0 ∧ a0 = 0 ∧ a1 < 0
(2, 2, 0, 0)
2
(x − r0 ) (x − r1 )
2
∆=0
c2 < 0 ∧ a1 = 0
(2, 2, 0, 0)
2
(x − z0 ) (x − z̄0 )
2
∆=0
c2 > 0 ∧ a1 = 0
(2, 1, 1, 0)
2
∆=0
c2 < 0 ∧ a0 6= 0 ∧ a1 < 0
2
(x − r0 ) (x − r1 )(x − r2 )
(2, 1, 1, 0)
(x − r0 ) (x − z0 )(x − z̄0 )
∆=0
a1 > 0 ∨ (c2 > 0 ∧ (a1 6= 0 ∨ c1 6= 0))
(1, 1, 1, 1)
(x − r0 )(x − r1 )(x − r2 )(x − r3 )
∆>0
c2 < 0 ∧ a1 < 0
(1, 1, 1, 1)
(x − z0 )(x − z̄0 )(x − z1 )(x − z̄1 )
∆>0
c2 > 0 ∨ a1 > 0
(1, 1, 1, 1)
(x − r0 )(x − r1 )(x − z0 )(x − z̄0 )
∆<0
I have verified that the conditions in that summary are correct and reproduce the results of the paper:
Graphical Discussion of the Roots of a Quartic Equation, E. L. Rees, The American Mathematical Monthly,
Vol. 29, No. 2, February 1922, pp. 51-55. This paper is based on analyzing the intersections of the auxiliary
quartic polynomial A(x) = x4 + c2 x2 + c0 and the linear polynomial L(x) = −c1 x. The intersections
correspond to the roots of c(x) = A(x) − L(x). The analysis of the conditions for ∆ = 0 are based on
intersections at which the line of L(x) is tangent to the graph of A(x).
Although the Wikipedia page is interesting mathematically, it suffers the fate of many discussions about
roots of low-degree polynomials. It is difficult to determine the logic necessary in a computer program
to classify the roots and compute the real-valued ones. The conditions in Table 1 appear to have been
generated using an optimization tool for Boolean expressions in order to generate a minimal set of tests, but
it is not immediately clear in which order these conditions should be tested in a computer program. Also,
the variables in some of the algebraic expressions for the roots can be real or non-real, and one must take
care to manipulate these appropriately in order to generate only the real-valued roots. For example, the
Cubic function page has a section entitled Vieta’s substitution. This is an extremely concise formulation for
the roots of a cubic polynomial. However, the wk are cube roots that are usually non-real, so you cannot
simply code the equations as they are stated when you want real roots. When expanded to allow a computer
program to generate real roots, the details are as complicated as those for Cardano’s method.
In the process of writing a quartic solver, I stumbled several times and had to revise the logic when test data
12
showed the code was not correct. One of those failures was based on the conditions for case (x − r0 )2 (x −
z0 )(x − z̄0 ) being incorrect, but the main contributor to the Wikipedia page was kind enough to fix that
quickly. (The Rees’ case of ∆ = 0, q > 0, s > 0, and r 6= 0 was missing in the pre-fix logic.)
Another failure occurred when using the approach of Ferrari to solve the depressed quartic by completing a
square. The process requires choosing a root to a related cubic polynomial, and I recall reading (somewhere)
that you can choose any root to the polynomial. I do not believe this is correct. The Wikipedia page, section
Ferrari’s solution,
√ has a cubic equation (4) for generating a root y to complete the square. That process
has a term β/(2 α + 2y), and the author mentions the potential division by zero and “. . . one thus need to
choose a root of the cubic equation such that α + 2y 6= 0. This is always possible unless for the depressed
equation x4 = 0.” It is not immediately clear that it is possible, but in fact it is—and it is possible to select
the correct one without √
trying all real roots of the cubic. However, it is important to know the sign of α + 2y,
because when negative, α + 2y is a non-real result. A computer program that generates the real roots must
take this into account. My implementation shows that you can choose a root for which α + 2y > 0 as long
as β 6= 0.
The author mentions “This implies β = 0, and thus that the depressed equation is bi-quadratic, and may be
solved by an easier method.” In fact, Ferrari’s approach is symbolic and does not apply when β = 0; you
have no option but to use the biquadratic solution. In turn, this means adding extra logic for the cases of
Table 1 when ∆ 6= 0 to fall back to the biquadratic solution when c1 = 0. I found that it is simpler (in a
program) to handle the case c1 = 0 separately before analyzing the sign of ∆.
That said, it is possible that α + 2y and β are both nearly zero, which can cause a problem numerically.
My solution is to replace that term by one not involving a division; see the section on Multiplicity Vector
(1, 1, 1, 1) for details.
Yet another pitfall with Table 1 is that it hides information about the sign of c0 . I found that is is simpler
(in a program) to handle the case c0 = 0 separately, followed by the test for c1 = 0. The if-then-else logic
for the other cases was easier to implement.
6.1
Processing the Root Zero
If c0 = 0, the depressed quartic is c(x) = x(x3 + c2 x + c1 ), so we know x = 0 is a root. The other roots may
be computed using the cubic root finder. That finder tests whether its constant term (c1 ) is zero, and if so
factors out x and calls the quadratic root finder. This recursive approach generates the appropriate root 0
and corresponding multiplicity.
6.2
The Biquadratic Case
If c0 6= 0 and c1 = 0, the depressed quartic is c(x) = x4 + c2 x2 + c0 = (x2 + c2 /2)2 + a1 , where a1 = c0 − c22 /4.
The discriminant for the quartic is ∆ = 16c0 (4c0 − c22 )2 = 256c0 a21 .
√
Suppose √
that ∆ < 0; then c0 < 0 and a1 < 0 and we can solve for x2 = −c2 /2 ± −a1 . The implication of
−c2 /2 − −a1 ≥ 0 is that c2 < 0 and c0 ≥ 0, but the latter conditionpis a contradiction to knowing c0 < 0.
√
√
Therefore, −c2 /2 − −a1 < 0 and we have two non-real roots z = ±ı c2 /2 + −a1 . The conditions c0 < 0
and a1 < 0 guarantee that the graph of c(x) p
intersects the x-axis in exactly two points, which then implies
√
√
−c2 /2 + −a1 > 0. We have real roots r1 = −c2 /2 + −a1 and r0 = −r1 .
13
2
Suppose that ∆ = 0; then a1 =
p0. Because c0 6= 0, we additionally know that c2 6= 0. If c2 > 0, x =
p−c2 /2
has non-real solutions z = ±ı c2 /2, each of multiplicity 2. If c2 < 0, the solutions are real r1 = −c2 /2
and r0 = −r1 .
Suppose that ∆ > 0; then c0 > 0 and a1 6= 0. We have three cases to consider:
√
≥ 0: The graph of c(x) does not intersect the x-axis. The implication of −c2 /2 + −a1 ≥ 0 is
≤ 0, which contradicts
our knowing c0 > 0. Therefore, the two numbers
on √
the right-hand side
p
√
x2 p
= −c2 /2 ± −a1 are negative and the non-real roots are z0 = ı c2 /2 − −a1 (and z̄0 ) and
√
= ı c2 /2 + −a1 (and z̄1 ).
√
2. c2 < 0 and a1 > 0: The graph of c(x) does not intersect the x-axis. Solve x2 = −c2 /2 ± ı a1 ; the two
numbers on the right-hand side are non-real. We can compute the complex-valued square roots of these
1/4
1/4
to produce the roots: z0 = c0 (cos(θ/2) + ı sin(θ/2)) (and z̄0 ) and z1 = c0 (− cos(θ/2) + ı sin(θ/2))
√
(and z̄1 ), where θ = atan2( a1 , −c2 /2).
1. c2
c0
of
z1
2
3. c2 < 0 and
√ a1 < 0: The graph of c(x) intersects the x-axis in four distinct points. Solve x =
−c2 /2 ± p−a1 where the two numbers on the
side are positive. The four distinct real roots
p right-hand
√
√
are r1 = −c2 /2 − −a1 , r0 = −r1 , r2 = −c2 /2 + −a1 , and r3 = −r2 .
6.3
Multiplicity Vector (3, 1, 0, 0)
A real root of multiplicity 3 must be a solution to c(x) = 0, c0 (x) = 0, c00 (x) = 0, but c000 (x) 6= 0. A solution
r0 must then be a root of f (x) = 3c0 (x) − xc00 (x) = 4c2 x + 3c1 ; thus, r0 = −3c1 /(4c2 ). The simple root
r1 is obtained from the zero root sum condition for the depressed polynomial, 3r0 + r1 = 0, which implies
r1 = −3r0 .
6.4
Multiplicity Vector (2, 2, 0, 0)
A root of multiplicity 2 must be a solution to c(x) = 0, c0 (x) = 0, but c00 (x) 6= 0. A solution r0 must then be a
root of f (x) = 4c(x) − xc0 (x) = 2c2 x2 + 3c1 x + 4c0 , where c2 6= 0. If the two distinct roots are x0 and x1 , then
the zero root sum condition for the depressed polynomial is 2x0 + 2x1 = 0. It must be that x1 = −x0 . The
only way the quadratic polynomial f (x) has two roots, one the negative of the other, is when the linear term
is zero; that is, c1 = 0. The depressed polynomial is of the form c(x) = x4 + c2 x2 + c0 = (x2 + c2 /2)2 + a1 /4.
To obtain two roots, each
and with x1 = −x0 , it is necessary that a1 = 0. If c2 <p
0, the
p of multiplicity 2 p
roots are real:
r
=
−
−c
/2
and
r
=
+
−c
/2.
If
c
>
0,
then
the
roots
are
non-real:
z
=
−ı
c2 /2
0
2
1
2
2
0
p
and z1 = +ı c2 /2.
6.5
Multiplicity Vector (2, 1, 1, 0)
The root of multiplicity 2 is necessarily real; otherwise, a repeated non-real root forces the multiplicity vector
to be (2, 2, 0, 0), which is a case we already analyzed. The double real root r0 must be a solution to c(r0 ) = 0
and c0 (r0 ) = 0 but c00 (r0 ) 6= 0. The zero root sum condition for the depressed polynomial is 2r0 + r1 + r2 = 0.
We also know that c1 6= 0; otherwise, c(x) = x4 + c2 x2 + c0 , which is the case of multiplicity vector (2, 2, 0, 0)
that was analyzed previously.
14
The common real root r0 for c(x) and c0 (x) must also be a root for the functions
f (x) = 4c(x) − xc0 (x) = 2c2 x2 + 3c1 x + 4c0
g(x) = c2 c0 (x) − 2xf (x) = −6c1 x2 + (2c22 − 8c0 )x + c1 c2
(28)
h(x) = 3c1 f (x) + c2 g(x) = (9c21 − 8c0 c2 + 2c32 )x + c1 (12c0 + c22 )
The double real root is therefore r0 = −c1 (12c0 + c22 )/(9c21 − 8c0 c2 + 2c32 ). To construct r1 and r2 , factor out
(x − r0 )2 from c(x) and solve the resulting quadratic equation,
c(x) = (x − r0 )2 (x2 + αx + β) = x4 + (α − 2r0 )x3 + (β − 2r0 α + r02 )x + (r02 α − 2r0 β)x + (r02 β)
Choose α = 2r0 and β = c2 + 2r0 α − r02 = c2 + 3r02 . When the discriminant α2 − 4β is positive, the roots
to the quadratic are the real roots r1 and r2 . When the discriminant is negative and the roots are nonreal
z0 and z̄0 . The zero root sum condition for the depressed polynomial is 2r0 + z0 + z̄0 = 0, which implies
the non-real
roots are of the form z0 = −r0 + ıv, and z̄0 = −r0 − ıv. Solving the quadratic equation shows
p
v = c2 + r02 .
6.6
Multiplicity Vector (1, 1, 1, 1)
We can implement a quartic root finder so that the case c0 = 0 is processed first, because a real root is zero
and the reduced polynomial is cubic. The algorithm for cubic root finding may then be applied. We can also
handle the case c0 6= 0 and c1 = 0, because the quartic is then biquadratic, x4 + c2 x2 + c0 , and the quadratic
root finding may be applies. In this section we therefore assume that c0 6= 0 and c1 6= 0.
Introduce a parameter t that will be determined later. Consider the expression
(x2 + t)2 = x4 + 2tx + t2 = −c2 x2 − c1 x − c0 + 2tx2 + t2 = (2t − c2 )x2 − c1 x + (t2 − c0 )
(29)
The right-hand side is a quadratic polynomial whose discriminant δ(t) = c21 − 4(2t − c2 )(t2 − c0 ) is a cubic
polynomial of t that has at least one real-valued root. Choose t̂ to be the largest root; then the right-hand
side of Equation (29) is the square of a quadratic polynomial,
(x2 + t̂ )2 = (αx − β)2
p
p
where α = 2t̂ − c2 and β = c1 /(2α) = Sign(c1 ) t̂2 − c0 . The number α must be a positive real because
2t̂ − c2 > 0. To see this, observe that δ(c2 /2) = c21 > 0 and δ(t) ≤ 0 for t ≥ t̂, which means c2 /2 < t̂.
Although the equation for β p
is theoretically correct, numerical problems might occur when α is small, so use
th other equation involving t̂2 − c0 ; this formulation suggests that if α is nearly zero, then so is c1 . We
now have two quadratic equations
x2 − αx + (t̂ + β) = 0, x2 + αx + (t̂ − β) = 0
The discriminant of the first quadratic is D0 = α2 − 4(t̂ + β) and the discriminant of the second quadratic is
D1 = α2 − 4(t̂ − β). Floating-point rounding errors when computing the discriminants that are theoretically
nearly zero can cause misclassifications of the root domains and multiplicities. However, we can use the
discriminant of the quartic and the auxiliary quantities to deduce the theoretically correct signs of D0 and
D1 and handle the numerical computations accordingly.
15
When ∆ > 0, c2 < 0, and a1 = 4c0 − c22 < 0, we know that there are four simple real roots. In this case we
know that D0 > 0 and D1 > 0. If rounding errors cause either quantity to be nonpositive, we can clamp them
to a small positive number
(or to zero to
√
√ avoid having the programmer specify the small positive number).
The roots are (α ± D0 )/2 and (−α ± D1 )/2.
When ∆ > 0, c2 > 0, and a1 > 0, we know that there are two complex conjugate pairs. In this case we know
that D0 < 0 and D1 < 0. If an implementation wants only real roots, we simply do not report any, even
when rounding errors cause either quantity to be nonnegative. However, if an implementation wants non-real
roots to be returned, we can clamp D0 and D1 to a small negative number
(or to zero to avoid
√ having the
√
programmer specify the small negative number). The roots are (α ± ı −D0 )/2 and (−α ± ı −D1 )/2.
When ∆ < 0, we know that there are two simple real roots and one complex conjugate pair. One of D0 and
D1 is positive, the other negative. If both are theoretically nearly zero, floating-point rounding errors can
prevent us from identifying the proper signs (so that we can clamp the results). However, we canpinfer the
ordering of D0 and D1 from β, specifically from the sign of c1 . Observe that D1 − D0 = 8β = √
8c1 / 2t̂ − c2 .
)/2 and
If c1 >√0, then D1 > D0 , so theoretically D1 > 0 and D0 < 0. The roots are (α ± ı −D0 √
(−α ± D1 )/2.
If
c
<
0,
then
D
<
D
,
so
theoretically
D
<
0
and
D
>
0.
The
roots
are
(α
±
D0 )/2
1
1
0
1
0
√
and (−α ± ı −D1 )/2. We can clamp the numerical computations accordingly.
6.7
A Mixed-Type Implementation
The straightforward floating-point implementation suffers the same problem as for the quadratic and cubic
polynomials. Floating-point rounding errors can cause a misclassification of the root domain or multiplicity. The implementation listed next uses exact rational arithmetic to provide a correct classification. The
precondition is that p4 6= 0.
v o i d S o l v e Q u a r t i c ( R e a l f p 0 , R e a l f p 1 , R e a l f p 2 , R e a l f p 3 , R e a l f p 4 , map<R e a l , i n t >& rmMap )
{
R a t i o n a l p0 = f p 0 , p1 = f p 1 , p2 = f p 2 , p3 = f p 3 , p4 = f p 4 ;
R a t i o n a l q0 = p0 / p4 ;
R a t i o n a l q1 = p1 / p4 ;
R a t i o n a l q2 = p2 / p4 ;
R a t i o n a l q3 = p3 / p4 ;
R a t i o n a l q 3 f o u r t h = q3 / 4 ;
Rational q3fourthSqr = q3fourth ∗ q3fourth ;
R a t i o n a l c0 = q0 − q 3 f o u r t h ∗ ( q1 − q 3 f o u r t h ∗ ( q2 − q 3 f o u r t h S q r ∗ 3 ) ) ;
R a t i o n a l c1 = q1 − 2 ∗ q 3 f o u r t h ∗ ( q2 − 4 ∗ q 3 f o u r t h S q r ) ;
R a t i o n a l c2 = q2 − 6 ∗ q 3 f o u r t h S q r ;
map<R a t i o n a l , i n t > rmLocalMap ;
S o l v e D e p r e s s e d Q u a r t i c ( c0 , c1 , c2 , rmLocalMap ) ;
f o r e a c h ( rm i n rmLocalMap )
{
R a t i o n a l r o o t = rm . f i r s t − q 3 f o u r t h ;
rmMap . i n s e r t ( ( R e a l ) r o o t , rm . s e c o n d ) ;
}
}
v o i d S o l v e D e p r e s s e d Q u a r t i c ( R a t i o n a l c0 , R a t i o n a l c1 , R a t i o n a l c2 , map<p a i r <R e a l , i n t >>& rmMap )
{
// H a n d l e t h e s p e c i a l c a s e o f c0 = 0 , i n w h i c h c a s e t h e p o l y n o m i a l
// r e d u c e s t o a d e p r e s s e d c u b i c .
i f ( c0 == 0 )
{
S o l v e D e p r e s s e d C u b i c ( c1 , c2 , rmMap ) ;
m a p i t e r a t o r i t e r = rmMap . f i n d ( 0 ) ;
i f ( i t e r != rmMap . end ( ) )
{
16
// The c u b i c h a s a r o o t o f z e r o , s o i n c r e a s e
++i t e r −>s e c o n d ;
its
multiplicity .
}
else
{
// The c u b i c d o e s n o t h a v e a r o o t o f z e r o .
rmMap . i n s e r t ( s t d : : m a k e p a i r ( mZero , 1 ) ) ;
I n s e r t one f o r t h e q u a r t i c .
}
return ;
}
// H a n d l e t h e s p e c i a l c a s e o f c1 = 0 , i n w h i c h c a s e t h e q u a r t i c i s a
// b i q u a d r a t i c x ˆ4 + c1 ∗ x ˆ2 + c0 = ( x ˆ2 + c2 / 2 ) ˆ 2 + ( c0 − c2 ˆ 2 / 4 ) .
i f ( c1 == 0 )
{
S o l v e B i q u a d r a t i c ( c0 , c2 , rmMap ) ;
return ;
}
// At t h i s ti me , c0 != 0 and c1 != 0 , w h i c h i s a r e q u i r e m e n t f o r t h e
// g e n e r a l s o l v e r t h a t must u s e a r o o t o f a s p e c i a l c u b i c p o l y n o m i a l .
R e a l c 0 s q r = c0 ∗ c0 , c 1 s q r = c1 ∗ c1 , c 2 s q r = c2 ∗ c2 ;
R a t i o n a l d e l t a = c 1 s q r ∗ (−27 ∗ c 1 s q r + 4 ∗ c2 ∗ ( 3 6 ∗ c0 − c 2 s q r ) )
+ 16 ∗ c0 ∗ ( c 2 s q r ∗ ( c 2 s q r − 8 ∗ c0 ) + 16 ∗ c 0 s q r ) ;
R a t i o n a l a0 = 12 ∗ c0 + c 2 s q r ;
R a t i o n a l a1 = 4 ∗ c0 − c 2 s q r ;
// C o r r e c t c l a s s i f i c a t i o n o f t h e s i g n o f d e l t a .
i f ( d e l t a > 0)
{
i f ( c2 < 0 && a1 < 0 )
{
// F o u r s i m p l e r e a l r o o t s .
map<R e a l , i n t > rmCubicMap ;
S o l v e C u b i c ( c 1 s q r − 4 ∗ c0 ∗ c2 , 8 ∗ c0 , 4 ∗ c2 , −8, rmCubicMap ) ;
R a t i o n a l t = ( R a t i o n a l ) GetMaxRoot ( rmCubicMap ) ;
R a t i o n a l a l p h a S q r = 2 ∗ t − c2 ;
R a t i o n a l alpha = ( R a t i o n a l ) s q r t (( double ) alphaSqr ) ;
d o u b l e sgnC1 = ( c1 > 0 ? 1 . 0 : − 1 . 0 ) ;
R a t i o n a l a r g = t ∗ t − c0 ;
R a t i o n a l b e t a = ( R a t i o n a l ) ( sgnC1 ∗ s q r t ( max ( ( d o u b l e ) a r g , 0 . 0 ) ) ) ;
R a t i o n a l D0 = a l p h a S q r − 4 ∗ ( t + b e t a ) ;
R a t i o n a l s q r t D 0 = ( R a t i o n a l ) s q r t ( max ( ( d o u b l e ) D0 , 0 . 0 ) ) ;
R a t i o n a l D1 = a l p h a S q r − 4 ∗ ( t − b e t a ) ;
R a t i o n a l s q r t D 1 = ( R a t i o n a l ) s q r t ( max ( ( d o u b l e ) D1 , 0 . 0 ) ) ;
R a t i o n a l r 0 = (+ a l p h a − s q r t D 0 ) / 2 ;
R a t i o n a l r 1 = (+ a l p h a + s q r t D 0 ) / 2 ;
R a t i o n a l r 2 = (− a l p h a − s q r t D 1 ) / 2 ;
R a t i o n a l r 3 = (− a l p h a + s q r t D 1 ) / 2 ;
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
rmMap . i n s e r t ( r2 , 1 ) ;
rmMap . i n s e r t ( r3 , 1 ) ;
}
e l s e // c2 >= 0 o r a1 >= 0
{
// Two complex−c o n j u g a t e p a i r s . The v a l u e s a l p h a , D0 , and D1 a r e
// t h o s e o f t h e i f −b l o c k .
// Complex z0 = ( a l p h a − i ∗ s q r t (−D0 ) ) / 2 ;
// Complex z 0 c o n j = ( a l p h a + i ∗ s q r t (−D0 ) ) / 2 ;
// Complex z1 = (− a l p h a − i ∗ s q r t (−D1 ) ) / 2 ;
// Complex z 1 c o n j = (− a l p h a + i ∗ s q r t (−D1 ) ) / 2 ;
}
}
e l s e i f ( d e l t a < 0)
{
// Two s i m p l e r e a l r o o t s , one complex−c o n j u g a t e p a i r .
map<R e a l , i n t > rmCubicMap ;
S o l v e C u b i c ( c 1 s q r − 4 ∗ c0 ∗ c2 , 8 ∗ c0 , 4 ∗ c2 , −8, rmCubicMap ) ;
R a t i o n a l t = ( R a t i o n a l ) GetMaxRoot ( rmCubicMap ) ;
R a t i o n a l a l p h a S q r = 2 ∗ t − c2 ;
R a t i o n a l alpha = ( R a t i o n a l ) s q r t (( double ) alphaSqr ) ;
17
d o u b l e sgnC1 = ( c1 > 0 ? 1 . 0 : − 1 . 0 ) ;
R a t i o n a l a r g = t ∗ t − c0 ;
R a t i o n a l b e t a = ( R a t i o n a l ) ( sgnC1 ∗ s q r t ( max ( ( d o u b l e ) a r g , 0 . 0 ) ) ) ;
R a t i o n a l r0 , r 1 ;
i f ( sgnC1 > 0 . 0 )
{
R a t i o n a l D1 = a l p h a S q r − 4 ∗ ( t − b e t a ) ;
R a t i o n a l s q r t D 1 = ( R a t i o n a l ) s q r t ( max ( ( d o u b l e ) D1 , 0 . 0 ) ) ;
r 0 = (− a l p h a − s q r t D 1 ) / 2 ;
r 1 = (− a l p h a + s q r t D 1 ) / 2 ;
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = ( a l p h a − i ∗ s q r t (−D0 ) ) / 2 ;
// Complex z 0 c o n j = ( a l p h a + i ∗ s q r t (−D0 ) ) / 2 ;
}
else
{
R a t i o n a l D0 = a l p h a S q r − 4 ∗ ( t + b e t a ) ;
R a t i o n a l s q r t D 0 = ( R a t i o n a l ) s q r t ( max ( ( d o u b l e ) D0 ,
r 0 = (+ a l p h a − s q r t D 0 ) / 2 ;
r 1 = (+ a l p h a + s q r t D 0 ) / 2 ;
0.0));
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = (− a l p h a − i ∗ s q r t (−D1 ) ) / 2 ;
// Complex z 0 c o n j = (− a l p h a + i ∗ s q r t (−D1 ) ) / 2 ;
}
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
}
else
{
// d e l t a = 0
i f ( a1 > 0 | | ( c2 > 0 && ( a1 != 0 | | c1 != 0 ) ) )
{
// One d o u b l e r e a l r o o t , one complex−c o n j u g a t e p a i r .
R a t i o n a l r 0 = −c1 ∗ a0 / ( 9 ∗ c 1 s q r − 2 ∗ c2 ∗ a1 ) ;
rmMap . i n s e r t ( r0 , 2 ) ;
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = −r o o t 0 − i ∗ s q r t ( c2 + r o o t 0 ˆ 2 ) ;
// Complex z 0 c o n j = −r o o t 0 + i ∗ s q r t ( c2 + r o o t 0 ˆ 2 ) ;
}
else
{
i f ( a0 != 0 )
{
// One d o u b l e r e a l r o o t , two s i m p l e r e a l r o o t s .
R a t i o n a l r 0 = −c1 ∗ a0 / ( 9 ∗ c 1 s q r − 2 ∗ c2 ∗ a1 ) ;
Rational alpha = 2 ∗ r0 ;
R a t i o n a l b e t a = c2 + 3 ∗ r 0 ∗ r 0 ;
Rational d i s c r = alpha ∗ alpha − 4 ∗ beta ;
R a t i o n a l temp1 = ( R a t i o n a l ) s q r t ( ( d o u b l e ) d i s c r ) ;
R a t i o n a l r 1 = (− a l p h a − temp1 ) / 2 ;
R a t i o n a l r 2 = (− a l p h a + temp1 ) / 2 ;
rmMap . i n s e r t ( r0 , 2 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
rmMap . i n s e r t ( r2 , 1 ) ;
}
else
{
// One t r i p l e r e a l r o o t , one s i m p l e r e a l r o o t .
R a t i o n a l r 0 = −3 ∗ c1 / ( 4 ∗ c2 ) ;
R a t i o n a l r 1 = −3 ∗ r 0 ;
rmMap . i n s e r t ( r0 , 3 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
}
}
}
v o i d S o l v e B i q u a d r a t i c ( R a t i o n a l c o n s t& c0 , R a t i o n a l c o n s t& c2 , map<R a t i o n a l , i n t >& rmMap )
{
// S o l v e 0 = x ˆ4 + c2 ∗ x ˆ2 + c0 = ( x ˆ2 + c2 / 2 ) ˆ 2 + a1 , w h e r e
// a1 = c0 − c2 ˆ 2 / 2 . We know t h a t c0 != 0 a t t h e t i m e o f t h e f u n c t i o n
18
// c a l l , s o x = 0 i s n o t a r o o t .
// D e l t a = 256∗ c0 ∗ a1 ˆ 2 .
The c o n d i t i o n c1 = 0 i m p l i e s t h e q u a r t i c
R a t i o n a l c 2 H a l f = c2 / 2 ;
R a t i o n a l a1 = c0 − c 2 H a l f ∗ c 2 H a l f ;
R a t i o n a l d e l t a = 256 ∗ c0 ∗ a1 ∗ a1 ;
i f ( d e l t a > 0)
{
i f ( c2 < 0 )
{
i f ( a1 < 0 )
{
// F o u r s i m p l e r o o t s .
R a t i o n a l temp0 = ( R a t i o n a l ) s q r t (−( d o u b l e ) a1 ) ;
R a t i o n a l temp1 = −c 2 H a l f − temp0 ;
R a t i o n a l temp2 = −c 2 H a l f + temp0 ;
R a t i o n a l r 1 = ( R a t i o n a l ) s q r t ( ( d o u b l e ) temp1 ) ;
R a t i o n a l r 0 = −r 1 ;
R a t i o n a l r 2 = ( R a t i o n a l ) s q r t ( ( d o u b l e ) temp2 ) ;
R a t i o n a l r 3 = −r 2 ;
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
rmMap . i n s e r t ( r2 , 1 ) ;
rmMap . i n s e r t ( r3 , 1 ) ;
}
else
// a1 > 0
{
// Two s i m p l e c o m p l e x c o n j u g a t e p a i r s .
// d o u b l e t h e t a D i v 2 = a t a n 2 ( s q r t ( a1 ) , −c2 / 2 ) / 2 . 0 ;
// d o u b l e c s = c o s ( t h e t a D i v 2 ) , s n = s i n ( t h e t a D i v 2 ) ;
// d o u b l e l e n g t h = pow ( c0 , 0 . 2 5 ) ;
// Complex z0 = l e n g t h ∗( c s + i ∗ s n ) ;
// Complex z 0 c o n j = l e n g t h ∗( c s − i ∗ s n ) ;
// Complex z1 = l e n g t h ∗(− c s + i ∗ s n ) ;
// Complex z 1 c o n j = l e n g t h ∗(− c s − i ∗ s n ) ;
}
}
else
// c2 >= 0
{
// Two s i m p l e c o m p l e x c o n j u g a t e p a i r s .
// Complex z0 = − i ∗ s q r t ( c2 /2 − s q r t (−a1 ) ) ;
// Complex z 0 c o n j = +i ∗ s q r t ( c2 /2 − s q r t (−a1 ) ) ;
// Complex z1 = − i ∗ s q r t ( c2 /2 + s q r t (−a1 ) ) ;
// Complex z 1 c o n j = +i ∗ s q r t ( c2 /2 + s q r t (−a1 ) ) ;
}
}
e l s e i f ( d e l t a < 0)
{
// Two s i m p l e r e a l r o o t s .
R a t i o n a l temp0 = ( R a t i o n a l ) s q r t (−( d o u b l e ) a1 ) ;
R a t i o n a l temp1 = −c 2 H a l f + temp0 ;
R a t i o n a l r 1 = ( R a t i o n a l ) s q r t ( ( d o u b l e ) temp1 ) ;
R a t i o n a l r 0 = −r 1 ;
rmMap . i n s e r t ( r0 , 1 ) ;
rmMap . i n s e r t ( r1 , 1 ) ;
// One c o m p l e x c o n j u g a t e p a i r .
// Complex z0 = − i ∗ s q r t ( c2 /2 + s q r t (−a1 ) ) ;
// Complex z 0 c o n j = +i ∗ s q r t ( c2 /2 + s q r t (−a1 ) ) ;
}
else
{
// d e l t a = 0
i f ( c2 < 0 )
{
// Two d o u b l e r e a l r o o t s .
R a t i o n a l r 1 = ( R a t i o n a l ) s q r t (−( d o u b l e ) c 2 H a l f ) ;
R a t i o n a l r 0 = −r 1 ;
rmMap . i n s e r t ( r0 , 2 ) ;
rmMap . i n s e r t ( r1 , 2 ) ;
}
else
// c2 > 0
{
19
// Two d o u b l e c o m p l e x c o n j u g a t e p a i r s .
// Complex z0 = − i ∗ s q r t ( c2 / 2 ) ;
// m u l t i p l i c i t y 2
// Complex z 0 c o n j = +i ∗ s q r t ( c2 / 2 ) ;
// m u l t i p l i c i t y 2
}
}
}
20
© Copyright 2026 Paperzz