Решите квадратное уравнение в C++

Я пытаюсь написать функцию на С++, которая решает для X, используя квадратное уравнение. Это то, что я написал изначально, и это работает, если для ответа нет комплексных чисел:

float solution1 = (float)(-1.0 * b) + (sqrt((b * b) - (4 * a * c)));
solution1 = solution1 / (2*a);

cout << "Solution 1: " << solution1 << endl;

float solution2 = (float)(-b) - (sqrt((b*b) - (4 * a * c)));
solution2 = solution2 / (2*a);
cout << "Solution 2: " << solution2;

Если, например, я использую уравнение: x^2 - x - 6, я правильно получаю решение 3, -2.

Мой вопрос в том, как бы я учитывал комплексные числа... например, учитывая уравнение:

x^2 + 2x + 5

Решив вручную, я бы получил -1 + 2i, -1 - 2i.

Ну, я думаю, два вопроса: могу ли я написать вышеизложенное лучше, а также учесть комплексное число?

Спасибо за любую помощь!


person Community    schedule 22.05.2009    source источник
comment
Другие ребята дали хорошие ответы, поэтому у меня нет причин пытаться их затмить ;) Однако, если вам нужно более общее решение уравнения ax^2+bx+c=0, помните, что a==0 должно быть допустимым стоимость. Это приведет к делению на ноль, поэтому вы должны позаботиться об этом случае отдельно. В этом случае это означало бы, что у вас осталось линейное уравнение с одним корнем. Ваше здоровье !   -  person ralphtheninja    schedule 22.05.2009
comment
Вы подразумеваете, что вас беспокоят комплексные корни, но как насчет комплексных коэффициентов в исходном уравнении?   -  person Jouni K. Seppänen    schedule 22.05.2009
comment
Комплексные коэффициенты требуют совершенно другого подхода. Так что это будет следующий вопрос :) убегает и заранее готовит ответ   -  person ralphtheninja    schedule 22.05.2009


Ответы (6)


Что-то вроде этого будет работать:

struct complex { double r,i; }
struct pair<T> { T p1, p2; }

pair<complex> GetResults(double a, double b, double c)
{
  pair<complex> result={0};

  if(a<0.000001)    // ==0
  {
    if(b>0.000001)  // !=0
      result.p1.r=result.p2.r=-c/b;
    else
      if(c>0.00001) throw exception("no solutions");
    return result;
  }

  double delta=b*b-4*a*c;
  if(delta>=0)
  {
    result.p1.r=(-b-sqrt(delta))/2/a;
    result.p2.r=(-b+sqrt(delta))/2/a;
  }
  else
  {
    result.p1.r=result.p2.r=-b/2/a;
    result.p1.i=sqrt(-delta)/2/a;
    result.p2.i=-sqrt(-delta)/2/a;
  }

  return result;
}

Таким образом, вы получаете одинаковые результаты как для реальных, так и для комплексных результатов (у реальных результатов просто мнимая часть установлена ​​на 0). С наддувом смотрелось бы еще красивее!

edit: исправлено для дельты и добавлена ​​проверка вырожденных случаев, таких как a=0. Бессонная ночь ftl!

person Blindy    schedule 22.05.2009
comment
Если sqrt завершается успешно, результат = 0. А если аргумент отрицательный, ваша программа аварийно завершает работу. Сначала вы должны проверить знак, а затем вычислить sqrt. Если бы знак был отрицательным, вы бы установили result.first.i = +sqrt(4*ac-bb)/2/a. (Зачем определять свой собственный тип, если есть прекрасный std::pair‹std::complex›?) - person MSalters; 22.05.2009
comment
должно быть delta=bb-4*ac, и принимать sqrt только тогда, когда delta›=0. delta=0 или a=0 допустимы случаи, когда у нас один корень. Что, если a=b=0 и c=1? - person Eric Bainville; 22.05.2009
comment
Что если? Это не квадратичная функция, и часть /2/a не сработает. Это работает достаточно хорошо, если delta=0, за исключением того, что вы вернете один и тот же результат дважды. - person MSalters; 22.05.2009
comment
Почему вы определяете пару и сложный тип? Оба уже существуют! - person Harper Shelby; 22.05.2009
comment
Портативный? ИДК.. Я написал все это в текстовом редакторе после 24 часов без сна, я удивлен, что это вообще компилируется ‹.‹ - person Blindy; 23.05.2009
comment
Я бы выбрал промежуточную переменную для хранения sqrt(delta): инженер во мне плачет всякий раз, когда видит ненужное дублирование операции с плавающей запятой... - person Jaime; 23.05.2009
comment
Извините за поздний комментарий, но новый пользователь использует этот код и получает ошибки. Почему вы используете sqrt(delta) вместо delta < 0? В этом случае большинство реализаций вернут NaN. - person NathanOliver; 05.09.2017
comment
Должно быть, опечатка, должно быть sqrt(-delta), то есть квадратный корень из абсолютного значения дельты. - person Blindy; 12.09.2017

Важное замечание ко всему этому. Решения, показанные в этих ответах и ​​в исходном вопросе, не являются надежными.

Хорошо известное решение (-b +- sqrt(b^2 - 4ac)) / 2a известно как ненадежное в вычислениях, когда ac очень мало по сравнению с b^2, потому что нужно вычесть два очень похожих значения. Для другого корня лучше использовать менее известное решение 2c / (-b --+ sqrt(b^2 -4ac)).

Устойчивое решение может быть рассчитано как:

temp = -0.5 * (b + sign(b) * sqrt(b*b - 4*a*c);
x1 = temp / a;
x2 = c / temp;

Использование знака (b) гарантирует, что мы не вычитаем два одинаковых значения.

Для OP измените это для комплексных чисел, как показано другими плакатами.

person Andrew Stein    schedule 22.05.2009
comment
+1 это значительно более надежно в вычислительном отношении, чем (-b +/- sqrt(b*b - 4*a*c))/(2a). Кстати: поскольку temp может быть 0,0, обычно требуется проверка перед делением. (например, a,b,c = 1,0,0). - person chux - Reinstate Monica; 07.06.2013
comment
sign(b) можно определить как +1 для b >= 0 и -1 для b < 0. - person quant_dev; 24.10.2020

У вас более или менее это есть, просто проверьте, является ли часть, которая находится внутри квадратного корня, отрицательной, а затем отслеживайте это отдельно в своих сокращениях.

person Jeff Moser    schedule 22.05.2009

Вы могли бы просто использовать std::complex<float> вместо float, чтобы получить поддержку комплексных чисел.

person sth    schedule 22.05.2009

Никая идея от Blindy:

typedef std::complex<double> complex;
using std::pair;
pair<complex> GetResults(double a, double b, double c)
{
  double delta=(b*b-4*a*c);
  double inv_2a = 1/2/a;
  if(delta >= 0) {
    double root = sqrt(delta);
    return std::make_pair(
        complex((-b-root)*inv_2a),
        complex((-b+root)*inv_2a);
  } else {
    double root = sqrt(-delta);
    return std::make_pair(
        complex(-b*inv_2a, -root*inv_2a)),
        complex(-b*inv_2a, +root*inv_2a)));
  }
}
person MSalters    schedule 22.05.2009

Я пробовал программу без использования заголовка «math.h», а также пробовал другую логику ... но моя программа может отвечать только на те квадратные уравнения, которые имеют коэффициент «x квадрат» как единицу ..... и где коэффициент «x ' можно выразить как сложение двух чисел, которые являются множителями постоянного члена. например. х квадрат +8х+16; х квадрат +7х+12; и т.д. здесь 8=4+4 и 16=4*4; здесь коэффициент при х может быть выражен как сложение двух чисел, которые являются множителями постоянного члена 16... Сам я им не полностью доволен, но попробовал что-то другое, не используя формулу решения квадратного уравнения. код есть;

        #include<iostream.h>
        #include<conio.h>
         class quadratic
              {
                int b,c ;
                float l,k;
                public:
               void solution();
              };
        void quadratic::solution()
             {
                 cout<<"Enter coefficient of x and the constant term of the quadratic eqn where coefficient of x square is one";
                 cin>>b>>c;

                 for(l=1;l<b;l++)
                  {
                   for(k=1;k<b;k++)
                    {
                     if(l+k==b&&l*k==c)
                        {
                          cout<<"x="<<-l<<"\t"<<"or"<<"\t"<<"x="<<-k;
                          cout<<"\n";
                         }
                    }
                }
            }
              void main()
                 {
                  quadratic a;
                   clrscr();
                  a.solution();
                  getch();
                 }
person Deepeshkumar    schedule 01.11.2012