Квадратное уравнение

от автора

Бытует мнение, что только 10% программистов способны написать двоичный поиск. Это мнение мы испытывать не будем, но что насчёт квадратного уравнения?

Поставим задачу конкретнее: решение квадратного уравнения вида ax2+bx+c=0 с целочисленными коэффициентами. На вход подаются три целых числа в рамках int (коэффициенты a, b и c). Программа должна всегда выдавать результат.
Казалось бы, плёвое дело: пять минут и готово! И вот спустя те самые пять минут имеем на выходе следующий код:

Код

int a, b, c; std::cin >> a >> b >> c;  long long discriminant = b*b - 4*a*c;  if (discriminant > 0)   std::cout << "D > 0; 2 корня:\n"             << "x1 = " << (-b + sqrt(discriminant))/(2*a) << "\n"             << "x2 = " << (-b - sqrt(discriminant))/(2*a) << std::endl; else if (discriminant == 0)   std::cout << "D = 0; 1 корень:\n"             << "x = " << -1.*b/(2*a) << std::endl; else if (discriminant < 0)   std::cout << "D < 0; нет корней." << std::endl; 

Всё здорово? Как бы не так. «Заказчик», пятиклассник Петя, недоволен: на его ввод программа выдала какие-то «nan» и «inf».

0 -1 -1 D > 0; 2 корня: x1 = inf x2 = nan 

Пожимаем плечами, добавляем условие для вырожденного случая:

Код

if (a == 0) {   if (b != 0)     std::cout << "a = 0; уравнение вырождается в линейное:\n"               << "x = " << -1.*c/b << std::endl;   else if (c == 0)     std::cout << "Все коэффициенты равны нулю; x - любое число." << std::endl;   else     std::cout << "Нет решений." << std::endl; } else {   // Предыдущий код, начиная с дискриминанта. } 

Стало лучше? А вот и нет.

1 0 -2 D > 0; 2 корня: x1 = 1.41421 x2 = -1.41421  49 7 -2 D > 0; 2 корня: x1 = 0.142857 x2 = -0.285714 

За такие ответы Петю в школе отругали: корень должен оставаться корнем, дробь — дробью. Чешем в затылке, вздыхаем и берёмся за код; структура за структурой, функция за функцией он распухает раз в десять, но основная функция при этом остаётся относительно неизменной, хотя и сильно прибавила в весе.

Код

Весь код этого этапа.

if (a == 0) {   if (b != 0)     std::cout << "a = 0; уравнение вырождается в линейное:\n"               << "x = " << fraction(-c,b).toString() << std::endl;   else if (c == 0)     std::cout << "Все коэффициенты равны нулю; x - любое число." << std::endl;   else     std::cout << "Нет решений." << std::endl; } else {   long long discriminant = b*b - 4*a*c;    if (discriminant > 0)   {     std::cout << "D > 0; 2 корня:\n";      radical dRoot (discriminant);      if (dRoot.isInteger())     {       std::cout << "x1 = " << fraction(-b + sqrt(discriminant), 2*a).toString() << "\n"                 << "x2 = " << fraction(-b - sqrt(discriminant), 2*a).toString() << std::endl;     }     else     {       std::string rational = fraction(-b, 2*a).toString(),                   irrational = fraction(radical(discriminant), 2*a).toString();       if (rational == "0")         std::cout << "x1 = " << irrational << "\n"                   << "x2 = " << "- " << irrational << std::endl;       else         std::cout << "x1 = " << rational << " + " << irrational << "\n"                   << "x2 = " << rational << " - " << irrational << std::endl;     }   }   else if (discriminant == 0)     std::cout << "D = 0; 1 корень:\n"               << "x = " << fraction(-b, 2*a).toString() << std::endl;   else if (discriminant < 0)     std::cout << "D < 0; нет корней." << std::endl; } 
1 0 -2 D > 0; 2 корня: x1 = ┐/2 x2 = - ┐/2  49 7 -2 D > 0; 2 корня: x1 = 1/7 x2 = -2/7 

Петя доволен, Петя принёс из школы пятёрку по математике родителям и шоколадку нам.
Прошло пять лет. Пётр перешёл в десятый класс. Там на уроке алгебры ему поведали о мнимых и комплексных числах. Откопав где-то на диске нашу программу, он пытается с её помощью — негодяй! — сделать домашнее задание. Но что это?

1 0 25 D < 0; нет корней. 

Негодующий Пётр приносит нам программу на доделку. Спустя пару часов чтения старого кода понимаем, что проблема решается… добавлением пары строк (честно говоря, я сам не ожидал).

Код

if (discriminant != 0) {   std::cout << "D != 0; 2 корня:\n";    radical dRoot (discriminant);    if (dRoot.isInteger())   {     std::cout << "x1 = " << fraction(-b + sqrt(discriminant), 2*a).toString() << "\n"               << "x2 = " << fraction(-b - sqrt(discriminant), 2*a).toString() << std::endl;   }   else   {     std::string rational = fraction(-b, 2*a).toString(),                 irrational = fraction(radical(discriminant), 2*a).toString();     if (rational == "0")       std::cout << "x1 = " << irrational << "\n"                 << "x2 = " << "- " << irrational << std::endl;     else       std::cout << "x1 = " << rational << " + " << irrational << "\n"                 << "x2 = " << rational << " - " << irrational << std::endl;   } } else if (discriminant == 0)   std::cout << "D = 0; 1 корень:\n"             << "x = " << fraction(-b, 2*a).toString() << std::endl; 

1 0 25 D != 0; 2 корня: x1 = i*5 x2 = - i*5  1 2 53 D != 0; 2 корня: x1 = -1 + i*2┐/13 x2 = -1 - i*2┐/13 

Петя заканчивает школу с пятёркой в аттестате, поступает в престижный университет и вылетает после первой же сессии.
Конец.
Итоговый код.

ссылка на оригинал статьи http://habrahabr.ru/post/175533/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *