File indexing completed on 2026-09-28 09:20:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathPoly_Quartic_HeaderFile
0015 #define _MathPoly_Quartic_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Core.hxx>
0019 #include <MathUtils_Poly.hxx>
0020 #include <MathPoly_Quadratic.hxx>
0021 #include <MathPoly_Cubic.hxx>
0022
0023 #include <cmath>
0024
0025
0026 namespace MathPoly
0027 {
0028 using namespace MathUtils;
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 inline MathUtils::PolyResult Quartic(double theA,
0048 double theB,
0049 double theC,
0050 double theD,
0051 double theE)
0052 {
0053 MathUtils::PolyResult aResult;
0054
0055
0056 if (MathUtils::IsZero(theA))
0057 {
0058 return Cubic(theB, theC, theD, theE);
0059 }
0060
0061
0062 const double aScale =
0063 std::max({std::abs(theA), std::abs(theB), std::abs(theC), std::abs(theD), std::abs(theE)});
0064 if (aScale < MathUtils::THE_ZERO_TOL)
0065 {
0066 aResult.Status = MathUtils::Status::InfiniteSolutions;
0067 return aResult;
0068 }
0069
0070
0071 const double a = theB / theA;
0072 const double b = theC / theA;
0073 const double c = theD / theA;
0074 const double d = theE / theA;
0075
0076
0077 const double aShift = a / 4.0;
0078 const double a2 = a * a;
0079 const double a3 = a2 * a;
0080 const double a4 = a2 * a2;
0081
0082 const double p = b - 3.0 * a2 / 8.0;
0083 const double q = c - a * b / 2.0 + a3 / 8.0;
0084 const double r = d - a * c / 4.0 + a2 * b / 16.0 - 3.0 * a4 / 256.0;
0085
0086
0087 const double aCoeffs[5] = {theE, theD, theC, theB, theA};
0088
0089
0090 if (MathUtils::IsZero(q))
0091 {
0092
0093 MathUtils::PolyResult aQuadResult = Quadratic(1.0, p, r);
0094
0095 if (!aQuadResult.IsDone())
0096 {
0097 aResult.Status = aQuadResult.Status;
0098 return aResult;
0099 }
0100
0101 aResult.Status = MathUtils::Status::OK;
0102 aResult.NbRoots = 0;
0103
0104 for (size_t i = 0; i < aQuadResult.NbRoots; ++i)
0105 {
0106 const double u = aQuadResult.Roots[i];
0107 if (u >= -MathUtils::THE_ZERO_TOL)
0108 {
0109 if (u <= MathUtils::THE_ZERO_TOL)
0110 {
0111
0112 aResult.Roots[aResult.NbRoots++] = -aShift;
0113 }
0114 else
0115 {
0116
0117 const double aSqrtU = std::sqrt(u);
0118 aResult.Roots[aResult.NbRoots++] = aSqrtU - aShift;
0119 aResult.Roots[aResult.NbRoots++] = -aSqrtU - aShift;
0120 }
0121 }
0122 }
0123
0124
0125 for (size_t i = 0; i < aResult.NbRoots; ++i)
0126 {
0127 aResult.Roots[i] = MathUtils::RefinePolyRoot(aCoeffs, 4, aResult.Roots[i]);
0128 }
0129 MathUtils::SortRoots(aResult.Roots.data(), aResult.NbRoots);
0130 aResult.NbRoots = MathUtils::RemoveDuplicateRoots(aResult.Roots.data(), aResult.NbRoots);
0131
0132 return aResult;
0133 }
0134
0135
0136 MathUtils::PolyResult aCubicResult = Cubic(1.0, 2.0 * p, p * p - 4.0 * r, -q * q);
0137
0138 if (!aCubicResult.IsDone() || aCubicResult.NbRoots == 0)
0139 {
0140 aResult.Status = MathUtils::Status::NumericalError;
0141 return aResult;
0142 }
0143
0144
0145 double z = aCubicResult.Roots[aCubicResult.NbRoots - 1];
0146
0147
0148 if (z < -MathUtils::THE_ZERO_TOL)
0149 {
0150
0151 for (size_t i = 0; i < aCubicResult.NbRoots; ++i)
0152 {
0153 if (aCubicResult.Roots[i] >= -MathUtils::THE_ZERO_TOL)
0154 {
0155 z = std::max(0.0, aCubicResult.Roots[i]);
0156 break;
0157 }
0158 }
0159 }
0160 z = std::max(0.0, z);
0161
0162
0163
0164
0165 const double s = std::sqrt(z);
0166 double u, v;
0167
0168 if (MathUtils::IsZero(s))
0169 {
0170
0171
0172 MathUtils::PolyResult aUVResult = Quadratic(1.0, p, r);
0173 if (!aUVResult.IsDone() || aUVResult.NbRoots < 2)
0174 {
0175
0176 u = p / 2.0;
0177 v = p / 2.0;
0178 }
0179 else
0180 {
0181 u = aUVResult.Roots[0];
0182 v = aUVResult.Roots[1];
0183 }
0184
0185
0186 aResult.Status = MathUtils::Status::OK;
0187 aResult.NbRoots = 0;
0188
0189 if (u <= MathUtils::THE_ZERO_TOL)
0190 {
0191 const double aSqrt = std::sqrt(std::max(0.0, -u));
0192 aResult.Roots[aResult.NbRoots++] = aSqrt - aShift;
0193 if (aSqrt > MathUtils::THE_ZERO_TOL)
0194 {
0195 aResult.Roots[aResult.NbRoots++] = -aSqrt - aShift;
0196 }
0197 }
0198
0199 if (v <= MathUtils::THE_ZERO_TOL)
0200 {
0201 const double aSqrt = std::sqrt(std::max(0.0, -v));
0202 aResult.Roots[aResult.NbRoots++] = aSqrt - aShift;
0203 if (aSqrt > MathUtils::THE_ZERO_TOL)
0204 {
0205 aResult.Roots[aResult.NbRoots++] = -aSqrt - aShift;
0206 }
0207 }
0208 }
0209 else
0210 {
0211
0212 const double aHalfPPlusZ = (p + z) / 2.0;
0213 const double aQOver2S = q / (2.0 * s);
0214
0215 u = aHalfPPlusZ - aQOver2S;
0216 v = aHalfPPlusZ + aQOver2S;
0217
0218
0219 MathUtils::PolyResult aQuad1 = Quadratic(1.0, s, u);
0220
0221
0222 MathUtils::PolyResult aQuad2 = Quadratic(1.0, -s, v);
0223
0224 aResult.Status = MathUtils::Status::OK;
0225 aResult.NbRoots = 0;
0226
0227 if (aQuad1.IsDone())
0228 {
0229 for (size_t i = 0; i < aQuad1.NbRoots; ++i)
0230 {
0231 aResult.Roots[aResult.NbRoots++] = aQuad1.Roots[i] - aShift;
0232 }
0233 }
0234
0235 if (aQuad2.IsDone())
0236 {
0237 for (size_t i = 0; i < aQuad2.NbRoots; ++i)
0238 {
0239 aResult.Roots[aResult.NbRoots++] = aQuad2.Roots[i] - aShift;
0240 }
0241 }
0242 }
0243
0244
0245 for (size_t i = 0; i < aResult.NbRoots; ++i)
0246 {
0247 aResult.Roots[i] = MathUtils::RefinePolyRoot(aCoeffs, 4, aResult.Roots[i]);
0248 }
0249
0250
0251 MathUtils::SortRoots(aResult.Roots.data(), aResult.NbRoots);
0252 aResult.NbRoots = MathUtils::RemoveDuplicateRoots(aResult.Roots.data(), aResult.NbRoots);
0253
0254 return aResult;
0255 }
0256
0257 }
0258
0259 #endif