Бытует мнение, что только 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
Петя заканчивает школу с пятёркой в аттестате, поступает в престижный университет и вылетает после первой же сессии.
Конец.
Итоговый код.
Автор: AraneusAdoro