예제 #1
0
        /// <summary>
        ///     Solves the equation \f$a0 + a1 x + a2 x^2 + a3 x^3 = 0\f$, returning all real values of
        ///		\f$x\f$ for which the equation is true. See https://en.wikipedia.org/wiki/Cubic_equation for the
        ///		algorithm used.
        /// </summary>
        public static IEnumerable <double> Solve(double a0, double a1, double a2, double a3)
        {
            DebugUtil.AssertFinite(a3, nameof(a3));
            DebugUtil.AssertFinite(a2, nameof(a2));
            DebugUtil.AssertFinite(a1, nameof(a1));
            DebugUtil.AssertFinite(a0, nameof(a0));
            if (Math.Abs(a3) <= 0.005)
            {
                foreach (double v in QuadraticFunction.Solve(a0, a1, a2))
                {
                    CubicFunction f = new CubicFunction(a0, a1, a2, a3);
                    yield return(f.NewtonRaphson(v));
                }
                yield break;
            }

            double delta0 = a2 * a2 - 3.0 * a3 * a1;
            double delta1 = 2.0 * a2 * a2 * a2 - 9.0 * a3 * a2 * a1 + 27.0 * a3 * a3 * a0;

            Complex p1 = Complex.Sqrt(delta1 * delta1 - 4.0 * delta0 * delta0 * delta0);

            // The sign we choose in the next equation is arbitrary. To prevent a divide-by-zero down the line, if p2 is
            // zero, we must choose the opposite sign to make it nonzero:
            Complex p2 = delta1 + p1;

            Complex c = Complex.Pow(0.5 * p2, (1.0 / 3.0));

            Complex xi = -0.5 + 0.5 * Complex.Sqrt(-3.0);

            List <Complex> roots = new List <Complex>
            {
                -1.0 / (3.0 * a3) * (a2 + c + delta0 / c),
                -1.0 / (3.0 * a3) * (a2 + xi * c + delta0 / (xi * c)),
                -1.0 / (3.0 * a3) * (a2 + xi * xi * c + delta0 / (xi * xi * c)),
            };

            foreach (Complex root in roots)
            {
                if (Math.Abs(root.Imaginary) <= 0.05)
                {
                    DebugUtil.AssertFinite(root.Real, nameof(root.Real));
                    yield return(root.Real);
                }
            }
        }
예제 #2
0
        /// <summary>
        ///     Solves the equation \f$d + c x + b x^2 + a x^3 = 0\f$, returning all real values of
        ///		\f$x\f$ for which the equation is true. See https://en.wikipedia.org/wiki/Cubic_equation for the
        ///		algorithm used.
        /// </summary>
        public static IEnumerable <double> Solve(double d, double c, double b, double a)
        {
            DebugUtil.AssertFinite(a, nameof(a));
            DebugUtil.AssertFinite(b, nameof(b));
            DebugUtil.AssertFinite(c, nameof(c));
            DebugUtil.AssertFinite(d, nameof(d));
            if (Math.Abs(a) <= 0.005f)
            {
                foreach (double v in QuadraticFunction.Solve(d, c, b))
                {
                    yield return(v);
                }
                yield break;
            }

            double delta0 = b * b - 3.0 * a * c;
            double delta1 = 2.0 * b * b * b - 9.0 * a * b * c + 27.0 * a * a * d;

            Complex p1 = Complex.Sqrt(delta1 * delta1 - 4.0 * delta0 * delta0 * delta0);

            // The sign we choose in the next equation is arbitrary. To prevent a divide-by-zero down the line, if p2 is
            // zero, we must choose the opposite sign to make it nonzero:
            Complex p2 = delta1 + p1;

            Complex C = Complex.Pow(0.5 * p2, (1.0 / 3.0));

            Complex xi = -0.5 + 0.5 * Complex.Sqrt(-3.0);

            List <Complex> roots = new List <Complex>
            {
                -1.0 / (3.0 * a) * (b + C + delta0 / C),
                -1.0 / (3.0 * a) * (b + xi * C + delta0 / (xi * C)),
                -1.0 / (3.0 * a) * (b + xi * xi * C + delta0 / (xi * xi * C)),
            };

            foreach (Complex root in roots)
            {
                if (Math.Abs(root.Imaginary) <= 0.05)
                {
                    DebugUtil.AssertFinite(root.Real, nameof(root.Real));
                    yield return(root.Real);
                }
            }
        }
예제 #3
0
        /// <summary>
        ///     Solves a general equation \f$a_0 + a_1 x + a_2 x^2 = 0\f$, returning all real values of
        ///		\f$x\f$ for which the equation is true using the 'abc-formula'.
        /// </summary>
        public static IEnumerable <double> Solve(double a0, double a1, double a2)
        {
            DebugUtil.AssertFinite(a0, nameof(a0));
            DebugUtil.AssertFinite(a1, nameof(a1));
            DebugUtil.AssertFinite(a2, nameof(a2));
            if (Math.Abs(a2) <= 0.005)
            {
                if (Math.Abs(a1) <= 0.005)
                {
                    // There are no roots found:
                    yield break;
                }
                else
                {
                    // There is a single root, found from solving the linear equation with a1=0. We find a point close
                    // to the root using the linear approximation, after which we approach the true solution using the
                    // Newton-Raphson method:
                    QuadraticFunction f = new QuadraticFunction(a0, a1, a2);
                    yield return(f.NewtonRaphson(-a0 / a1));
                }
                yield break;
            }

            double x1 = 0.5 * (-a1 + Math.Sqrt(a1 * a1 - 4.0 * a0 * a2)) / a2;
            double x2 = 0.5 * (-a1 - Math.Sqrt(a1 * a1 - 4.0 * a0 * a2)) / a2;

            if (Double.IsNaN(x1) == false)
            {
                yield return(x1);
            }

            if (Double.IsNaN(x2) == false)
            {
                yield return(x2);
            }
        }
예제 #4
0
 /// <summary>
 ///     Solves the equation \f$a_0 + a_1 x + a_2 x^2 = 0\f$, returning all real values of
 ///		\f$x\f$ for which the equation is true using the 'abc-formula' using the parameters
 ///     in this instance of QuadraticFunction.
 /// </summary>
 public IEnumerable <float> Roots()
 {
     return(QuadraticFunction.Solve(a0, a1, a2));
 }