Loading...
Searching...
No Matches
Quartic.cpp
1/***************************************************************************
2 * Copyright (C) 2016 by Саша Миленковић *
3 * sasa.milenkovic.xyz@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * ( http://www.gnu.org/licenses/gpl-3.0.en.html ) *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21/*
22 * Modified by Gaurav Jalan @HiPeRLab Berkeley
23 * Added new root storing method
24 * Discarded imaginary root finder part
25 * Added new Quartic namespace
26 */
27
28#include <cmath>
29#include "./Quartic.h"
30
31namespace Quartic
32{
33
34 //---------------------------------------------------------------------------
35 // solve cubic equation x^3 + a*x^2 + b*x + c
36 // x - array of size 3
37 // In case 3 real roots: => x[0], x[1], x[2], return 3
38 // 2 real roots: x[0], x[1], return 2
39 // 1 real root : x[0], x[1] ± i*x[2], return 1
40 unsigned int solveP3(double a, double b, double c, double *x)
41 {
42 double a2 = a * a;
43 double q = (a2 - 3 * b) / 9;
44 double r = (a * (2 * a2 - 9 * b) + 27 * c) / 54;
45 double r2 = r * r;
46 double q3 = q * q * q;
47 double A, B;
48 if (r2 < q3)
49 {
50 double t = r / sqrt(q3);
51 if (t < -1)
52 t = -1;
53 if (t > 1)
54 t = 1;
55 t = acos(t);
56 a /= 3;
57 q = -2 * sqrt(q);
58 x[0] = q * cos(t / 3) - a;
59 x[1] = q * cos((t + M_2PI) / 3) - a;
60 x[2] = q * cos((t - M_2PI) / 3) - a;
61 return 3;
62 }
63 else
64 {
65 A = -pow(fabs(r) + sqrt(r2 - q3), 1. / 3);
66 if (r < 0)
67 A = -A;
68 B = (0 == A ? 0 : q / A);
69
70 a /= 3;
71 x[0] = (A + B) - a;
72 x[1] = -0.5 * (A + B) - a;
73 x[2] = 0.5 * sqrt(3.) * (A - B);
74 if (fabs(x[2]) < eps)
75 {
76 x[2] = x[1];
77 return 2;
78 }
79
80 return 1;
81 }
82 }
83
84 //---------------------------------------------------------------------------
85 // solve quartic equation x^4 + a*x^3 + b*x^2 + c*x + d
86 // Attention - this function returns dynamically allocated array. It has to be released afterwards.
87 size_t solve_quartic(const double &a, const double &b, const double &c, const double &d, double root[])
88 {
89 double a3 = -b;
90 double b3 = a * c - 4. * d;
91 double c3 = -a * a * d - c * c + 4. * b * d;
92
93 // initialise counters for real and imaginary roots
94 int rCnt = 0;
95 // cubic resolvent
96 // y^3 − b*y^2 + (ac−4d)*y − a^2*d−c^2+4*b*d = 0
97
98 double x3[3];
99 unsigned int iZeroes = solveP3(a3, b3, c3, x3);
100
101 double q1, q2, p1, p2, D, sqD, y;
102
103 y = x3[0];
104 // The essence - choosing Y with maximal absolute value.
105 if (iZeroes != 1)
106 {
107 if (fabs(x3[1]) > fabs(y))
108 y = x3[1];
109 if (fabs(x3[2]) > fabs(y))
110 y = x3[2];
111 }
112
113 // h1+h2 = y && h1*h2 = d <=> h^2 -y*h + d = 0 (h === q)
114
115 D = y * y - 4 * d;
116 if (fabs(D) < eps) // in other words - D==0
117 {
118 q1 = q2 = y * 0.5;
119 // g1+g2 = a && g1+g2 = b-y <=> g^2 - a*g + b-y = 0 (p === g)
120 D = a * a - 4 * (b - y);
121 if (fabs(D) < eps) // in other words - D==0
122 p1 = p2 = a * 0.5;
123
124 else
125 {
126 sqD = sqrt(D);
127 p1 = (a + sqD) * 0.5;
128 p2 = (a - sqD) * 0.5;
129 }
130 }
131 else
132 {
133 sqD = sqrt(D);
134 q1 = (y + sqD) * 0.5;
135 q2 = (y - sqD) * 0.5;
136 // g1+g2 = a && g1*h2 + g2*h1 = c ( && g === p ) Krammer
137 p1 = (a * q1 - c) / (q1 - q2);
138 p2 = (c - a * q2) / (q1 - q2);
139 }
140
141 // solving quadratic eq. - x^2 + p1*x + q1 = 0
142 D = p1 * p1 - 4 * q1;
143 if (!(D < 0.0))
144 {
145 // real roots filled from left
146 sqD = sqrt(D);
147 root[rCnt] = (-p1 + sqD) * 0.5;
148 ++rCnt;
149 root[rCnt] = (-p1 - sqD) * 0.5;
150 ++rCnt;
151 }
152
153 // solving quadratic eq. - x^2 + p2*x + q2 = 0
154 D = p2 * p2 - 4 * q2;
155 if (!(D < 0.0))
156 {
157 sqD = sqrt(D);
158 root[rCnt] = (-p2 + sqD) * 0.5;
159 ++rCnt;
160 root[rCnt] = (-p2 - sqD) * 0.5;
161 ++rCnt;
162 }
163
164 return rCnt;
165 }
166} // namespace Quartic