Решение квадратных, кубических и биквадратных уравнений на C#

суббота, 25 июня 2011, Александр Краковецкий

Выражение вида f(x)=0 называется уравнением. Число х называется корнем уравнения, если при его подстановке уравнение обращается в верное равенство. В статье рассмотрим методы решения уравнений - как точных, так и численных (приближенных).

Решение квадратных уравнений

Квадратным уравнением называется уравнение вида

alt text

Классическая формула для нахождения его корней (действительных и комплексных):

alt text

где выражение D = b2 − 4ac называется дискриминантом уравнения, от его значения зависит количество и характер решений:

  • Если D>0, то корней уравнения будет два и оба они будут действительными числами;
  • Если D=0, то будет лишь один дейсвительный корень уравнения;
  • Если D<0, то действительных решений уравнения нет, а корни будут комплексными.

Для нахождения действительных корней напишем метод SolveQuadraticEquation, входными параметрами которого будут значения при коэффициентах a, b и c, а на выходе – набор значений – решений уравнения:

public Tuple<double,double> SolveQuadraticEquation(double a, double b, double c)
{
  double discRoot = Math.Sqrt(b*b-4.0*a*c);
  double x1 = (-b + discRoot) / (2 * a);
  double x2 = (-b - discRoot) / (2 * a);
  return Tuple.Create(x1, x2);
}

Для работы с комплексными числами в .NET 4.0 был добавлен класс Complex, с помощью которого мы перепишем наш метод для нахождения также и комплексных корней уравнения:

public Tuple<Complex, Complex> SolveQuadraticEquationComplex(double a, double b, double c)
{
  double det = b * b - 4 * a * c;
  double absRoot = Math.Sqrt(Math.Abs(det));
  Complex root = det < 0 ? new Complex(0, absRoot) : new Complex(absRoot, 0);
  Complex q = -0.5 * (b + Math.Sign(b) * root);
  return Tuple.Create(q / a, c / q);
}

Нужно заметить, что в данном случае возвращаться будет набор значений типа Complex.

Для тестирования написанных функций возьмем следующие три квадратных уравнения:

  • 5x2+10x+200=0; данное уравнение не имеет действительных корней, но имеет пару сопряженных комплексных корней: x1 = -1-6,2449979983984i, x2 = -1+6,2449979983984i;
  • x2-8x+16=0; данное уравнение имеет один двукратный корень x1=x2=4;
  • x2-5x+6=0; данное уравнение имеет два различных корня x1=2, x2=3.

Напишем программу для решения этих уравнений:

namespace ConsoleApp
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Numerics;
    using NumericalMethods.Equations;

    class Program
    {
        static void Main(string[] args)
        {
            // Redirect output to a file named Files.txt and write file list.
            StreamWriter writer = new StreamWriter(@"out.txt");
            writer.AutoFlush = true;
            Console.SetOut(writer);

            Console.WriteLine("5x^2 - 10x + 200 = 0");
            var results = EquationSolver.SolveQuadraticEquationComplex(5, 10, 200);
            Print(results);

            Console.WriteLine("x^2 - 8x + 16 = 0");
            results = EquationSolver.SolveQuadraticEquationComplex(1, -8, 16);
            Print(results);

            Console.WriteLine("x^2 - 5x + 6 = 0");
            results = EquationSolver.SolveQuadraticEquationComplex(1, -5, 6);
            Print(results);
        }

        private static void Print(IEnumerable<Complex> results)
        {
            for (int i = 0; i < results.Count(); i++)
            {
                Console.WriteLine("x{0} = {1}", i, results.ToList()[i]);
            }
            Console.WriteLine();
        }
    }
}

На выходе получим:

Out.txt:

5x^2 - 10x + 200 = 0
x0 = (-1, -6,2449979983984)
x1 = (-1, 6,2449979983984)

x^2 - 8x + 16 = 0
x0 = (4, 0)
x1 = (4, 0)

x^2 - 5x + 6 = 0
x0 = (3, 0)
x1 = (2, 0)

Воспользуемся WolframAlpha для проверки значений:

Первое уравнение, второе уравнение, третье уравнение.

Решение кубических уравнений

Кубическим уравнением называется уравнение третьего порядка, которое имеет вид

alt text

Кубическое уравнение всегда имеет 3 корня, которые могут быть как вещественными, так и комплексными. Для решения кубических уравнений используется метод Виета-Кардано.

Формулы Кардано и Виета требуют применения специальных функций, и в том случае, когда требуется провести большую серию вычислений корней кубического уравнения с не слишком сильно меняющимися коэффициентами, более быстрым алгоритмом является использование метода Ньютона или других итерационных методов (с нахождением начального приближения по формулам Кардано-Виета), о которых мы поговорим дальше.

Рассмотрим в качестве примера следующие кубические уравнения:

  • x^3 - 6x^2 + 11x - 6 = 0
  • x^3 - 6x^2 + 11x + 6 = 0

Напишем программу для решения кубических уравнений с помощью метода Виета-Кардано:

public static IEnumerable<Complex> SolveCubicEquation(double a, double b, double c)
        {
            var Q = (Math.Pow(a, 2) - 3 * b) / 9;
            var R = (2 * Math.Pow(a, 3) - 9 * a * b + 27 * c) / 54;

            if (Math.Pow(R, 2) < Math.Pow(Q, 3))
            {
                var t = Math.Acos(R / Math.Sqrt(Math.Pow(Q, 3))) / 3;
                var x1 = -2 * Math.Sqrt(Q) * Math.Cos(t) - a / 3;
                var x2 = -2 * Math.Sqrt(Q) * Math.Cos(t + (2 * Math.PI / 3)) - a / 3;
                var x3 = -2 * Math.Sqrt(Q) * Math.Cos(t - (2 * Math.PI / 3)) - a / 3;
                return new List<Complex> 
                { 
                    new Complex(x1, 0), new Complex(x2, 0), new Complex(x3, 0)
                };
            }
            else
            {
                var A = -Math.Sign(R) * Math.Pow(Pol(R) + Math.Sqrt(Math.Pow(R, 2) - Math.Pow(Q, 3)), (1.0 / 3.0));
                var B = (A == 0) ? 0.0 : Q / A;

                var x1 = (A + B) - a / 3;

                if (A == B)
                {
                    var x2 = -A - a / 3;
                    return new List<Complex>  { new Complex(x1, 0), new Complex(x2, 0), new Complex(double.NaN, double.NaN) };
                }
                else
                {
                    Complex x2 = new Complex(-(A + B) / 2 - a / 3, -Math.Sqrt(3) * (A - B) / 2);
                    Complex x3 = new Complex(-(A + B) / 2 - a / 3, Math.Sqrt(3) * (A - B) / 2);
                    return new List<Complex>  { new Complex(x1, 0), x2, x3};
                }
            }
        }

Напишем программу для тестирования метода:

namespace ConsoleApp
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Numerics;
    using NumericalMethods.Equations;

    class Program
    {
        static void Main(string[] args)
        {
            // Redirect output to a file named Files.txt and write file list.
            StreamWriter writer = new StreamWriter(@"out.txt");
            writer.AutoFlush = true;
            Console.SetOut(writer);

            Console.WriteLine("x^3 - 6x^2 + 11x - 6 = 0");
            var results = EquationSolver.SolveCubicEquation(1, -6, 11, -6);
            Print(results);

            Console.WriteLine("x^3 - 6x^2 + 11x + 6 = 0");
            results = EquationSolver.SolveCubicEquation(1, -6, 11, 6);
            Print(results);
        }

        private static void Print(IEnumerable<Complex> results)
        {
            for (int i = 0; i < results.Count(); i++)
            {
                Console.WriteLine("x{0} = {1}", i, results.ToList()[i]);
            }
            Console.WriteLine();
        }
    }
}

Результат выполнения:

Out.txt:

x^3 - 6x^2 + 11x - 6 = 0
x0 = (1, 0)
x1 = (3, 0)
x2 = (2, 0)

x^3 - 6x^2 + 11x + 6 = 0
x0 = (-0,434841368216901, 0)
x1 = (3,21742068410845, 1,85643189109788)
x2 = (3,21742068410845, -1,85643189109788)

Решим эти же уравнения с помощью WolframAlpha.

Первое уравнение, втором случае, второе уравнение.

Решение биквадратных уравнений

Биквадратное уравнение - уравнение четвёртой степени вида

ax4 + bx2 + c = 0

где a,b,c — заданные комплексные числа и a != 0. Подстановкой y = x2 сводится к квадратному уравнению относительно y. Такой переход от одной неизвестной величины к другой называется методом замены неизвестных.

Рассмотрим в качестве примера кубические уравнения:

  • 5x^4 - 10x^2 + 200 = 0
  • x^4 - 8x^2 + 16 = 0
  • x^4 - 5x^2 + 6 = 0

Таким образом немного модифицируем первую функцию для решения биквадратных уравнений:

public static IEnumerable<Complex> SolveBiQuadraticEquation(double a, double b, double c)
        {
            var sol = SolveQuadraticEquationComplex(a, b, c).ToList();
            return new List<Complex> { 
                Complex.Sqrt(sol[0]), 
                -Complex.Sqrt(sol[0]),
                Complex.Sqrt(sol[1]), 
                -Complex.Sqrt(sol[1])};
        }

Напшем программу для тестирования метода:

namespace ConsoleApp
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Numerics;
    using NumericalMethods.Equations;

    class Program
    {
        static void Main(string[] args)
        {
            // Redirect output to a file named Files.txt and write file list.
            StreamWriter writer = new StreamWriter(@"out.txt");
            writer.AutoFlush = true;
            Console.SetOut(writer);

            Console.WriteLine("5x^4 - 10x^2 + 200 = 0");
            var results = EquationSolver.SolveBiQuadraticEquation(5, 10, 200);
            Print(results);

            Console.WriteLine("x^4 - 8x^2 + 16 = 0");
            results = EquationSolver.SolveBiQuadraticEquation(1, -8, 16);
            Print(results);

            Console.WriteLine("x^4 - 5x^2 + 6 = 0");
            results = EquationSolver.SolveBiQuadraticEquation(1, -5, 6);
            Print(results);
        }

        private static void Print(IEnumerable<Complex> results)
        {
            for (int i = 0; i < results.Count(); i++)
            {
                Console.WriteLine("x{0} = {1}", i, results.ToList()[i]);
            }
            Console.WriteLine();
        }
    }
}

На выходе получим такие результаты:

Out.txt

5x^4 - 10x^2 + 200 = 0
x0 = (1,63164875514566, -1,91370783040891)
x1 = (-1,63164875514566, 1,91370783040891)
x2 = (1,63164875514566, 1,91370783040891)
x3 = (-1,63164875514566, -1,91370783040891)

x^4 - 8x^2 + 16 = 0
x0 = (2, 0)
x1 = (-2, 0)
x2 = (2, 0)
x3 = (-2, 0)

x^4 - 5x^2 + 6 = 0
x0 = (1,73205080756888, 0)
x1 = (-1,73205080756888, 0)
x2 = (1,4142135623731, 0)
x3 = (-1,4142135623731, 0)

По ссылкам раз, два, три можно убедиться в правильности решений.


Ищите нас в интернетах!

Комментарии

Свежие вакансии