Поставим задачу конкретнее: решение квадратного уравнения вида 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/
Добавить комментарий