mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
Fix quartic roots when depressed cubic only has single real root (#838)
This commit is contained in:
@@ -122,12 +122,18 @@ std::array<Real, 4> quartic_roots(Real a, Real b, Real c, Real d, Real e) {
|
||||
// z^3 + 2pz^2 + (p^2 - 4r)z - q^2 = 0.
|
||||
auto z_roots = cubic_roots(Real(1), 2*p, p*p - 4*r, -q*q);
|
||||
// z = s^2, so s = sqrt(z).
|
||||
// Hence we require a root > 0, and for the sake of sanity we should take the largest one:
|
||||
Real largest_root = std::numeric_limits<Real>::lowest();
|
||||
for (auto z : z_roots) {
|
||||
if (z > largest_root) {
|
||||
largest_root = z;
|
||||
}
|
||||
}
|
||||
// No real roots:
|
||||
if (z_roots.back() <= 0) {
|
||||
if (largest_root <= 0) {
|
||||
return roots;
|
||||
}
|
||||
Real s = sqrt(z_roots.back());
|
||||
|
||||
Real s = sqrt(largest_root);
|
||||
// s is nonzero, because we took care of the biquadratic case.
|
||||
Real v = (p + s*s + q/s)/2;
|
||||
Real u = v - q/s;
|
||||
|
||||
@@ -109,13 +109,13 @@ void test_zero_coefficients()
|
||||
root = static_cast<Real>(dis(gen));
|
||||
}
|
||||
std::sort(r.begin(), r.end());
|
||||
Real a = 1;
|
||||
Real b = -(r[0] + r[1] + r[2] + r[3]);
|
||||
Real c = r[0]*r[1] + r[0]*r[2] + r[0]*r[3] + r[1]*r[2] + r[1]*r[3] + r[2]*r[3];
|
||||
Real d = -(r[0]*r[1]*r[2] + r[0]*r[1]*r[3] + r[0]*r[2]*r[3] + r[1]*r[2]*r[3]);
|
||||
Real e = r[0]*r[1]*r[2]*r[3];
|
||||
a = 1;
|
||||
b = -(r[0] + r[1] + r[2] + r[3]);
|
||||
c = r[0]*r[1] + r[0]*r[2] + r[0]*r[3] + r[1]*r[2] + r[1]*r[3] + r[2]*r[3];
|
||||
d = -(r[0]*r[1]*r[2] + r[0]*r[1]*r[3] + r[0]*r[2]*r[3] + r[1]*r[2]*r[3]);
|
||||
e = r[0]*r[1]*r[2]*r[3];
|
||||
|
||||
auto roots = quartic_roots(a, b, c, d, e);
|
||||
roots = quartic_roots(a, b, c, d, e);
|
||||
// I could check the condition number here, but this is fine right?
|
||||
CHECK_ULP_CLOSE(r[0], roots[0], 160);
|
||||
CHECK_ULP_CLOSE(r[1], roots[1], 260);
|
||||
@@ -124,6 +124,23 @@ void test_zero_coefficients()
|
||||
}
|
||||
}
|
||||
|
||||
void issue_825() {
|
||||
using std::sqrt;
|
||||
using std::cbrt;
|
||||
double a = 1;
|
||||
double b = 1;
|
||||
double c = 1;
|
||||
double d = 1;
|
||||
double e = -4;
|
||||
std::array<double, 4> roots = boost::math::tools::quartic_roots<double>(a, b, c, d, e);
|
||||
// The real roots are 1 and -1.6506
|
||||
// Wolfram alpha: Roots[x^4 + x^3 + x^2 + x == 4]
|
||||
double expected = (-2 - cbrt(25/(3*sqrt(6.0) - 7)) + cbrt(5*(3*sqrt(6.0) - 7)))/3;
|
||||
CHECK_ULP_CLOSE(expected, roots[0], 5);
|
||||
CHECK_ULP_CLOSE(1.0, roots[1], 5);
|
||||
CHECK_NAN(roots[2]);
|
||||
CHECK_NAN(roots[3]);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -132,5 +149,6 @@ int main()
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
test_zero_coefficients<long double>();
|
||||
#endif
|
||||
issue_825();
|
||||
return boost::math::test::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user