Блок задач

8. Чёрные ящики

Темы
Сложность 2

Задача «Комплексные числа»

Задание

Самостоятельно реализовать класс комплексных чисел, аналогичный std::complex.

Описание

Основной интерфейс класса:

class Complex {
public:
    Complex(double re = 0.0, double im = 0.0);

    // Получение действительной части
    double Re() const;

    // Получение мнимой части
    double Im() const;

    Complex &operator=(double x);
    Complex &operator+=(double x);
    Complex &operator-=(double x);
    Complex &operator*=(double x);
    Complex &operator/=(double x);

    Complex &operator=(const Complex &cplx);
    Complex &operator+=(const Complex &cplx);
    Complex &operator-=(const Complex &cplx);
    Complex &operator*=(const Complex &cplx);
    Complex &operator/=(const Complex &cplx);
};

Помимо операторов-членов класса необходимо реализовать ряд глобальных функций и операций:

  • Арифметические операции. Должны работать как над парой комплексных чисел, так и над сочетанием комплексных чисел с обычными реальными числами (double).
  • Операции проверки на равенство. Точная проверка на равенство/неравенство как пары комплексных чисел, так и сочетания комплексных чисел с обычными реальными числами (double). Для проверки на равенство с погрешностью реализовать функцию equals(), принимающую помимо сравниваемых объектов еще и величину допустимой погрешности.
  • Операции форматированного ввода/вывода в поток. Вывод комплексного числа в поток в формате (re, im), например, (5, -1); чтение комплексного числа в этом же формате. Допускается чтение комплексного числа в формате re, например, 5, что рассматривается как равенство мнимой части нулю.
  • Представление комплексного числа в полярных координатах. abs(), arg().
  • Создание комплексного числа в полярных координатах. polar().
  • Построение сопряженного комплексного числа. conj().
  • Вычисление квадрата модуля комплексного числа. norm().
  • Тригонометрические функции. sin(), cos(), tan() — над комплексными числами.
  • Функции, связанные со степенью. Экспонента exp(), логарифм log(), log10() — над комплексными числами.
  • Возведение в степень. pow() — возведение комплексного числа в реальную степень, возведение реального числа в комплексную степень, возведение комплексного числа в комплексную степень.
  • Извлечение квадратного корня. sqrt().

Тесты

Приведем несколько тестов, демонстрирующих удобство работы с классом.

Простейшие арифметические операции с комплексными числами. Ввод комплексных чисел из потока пользователем.

Complex x = 1;  // (1, 0)
Complex y(1, -1);   // (1, -1)
Complex z;      // (0, 0)

std::cout << "x = " << x << ", y = " << y << std::endl;

while (true) {
     std::cout << "z = ";
     std::cin >> z;

     if (!std::cin)
         break;

     std::cout << std::endl;
     std::cout << "x + z = " << (x + z) << std::endl;
     std::cout << "z - y = " << (z - y) << std::endl;
     std::cout << "2 * z = " << (2 * z) << std::endl;
     std::cout << "z / y = " << (z / y) << std::endl;
     // любые другие операции на усмотрение студента
     std::cout << std::endl;
}

Проверка на равенство, обобщение комплексных чисел на функции cos(), sin(), и др. Ввод комплексных чисел из файла.

Complex x;
const Complex i(0, 1);
std::ifstream file("test.txt");

while (true) {
    file >> x;
    if (!file)
        break;

    std::cout << "x = " << x << std::endl;

    Complex left = exp(i*x);
    Complex right = cos(x)+i*sin(x);

    std::cout << "exp(i*x)\t=\t" << left << std::endl;
    std::cout << "cos(x)+i*sin(x)\t=\t" << right << std::endl;

    if (left - right == 0)
        std::cout << "HEH! That Euler was a really smart guy!" << std::endl;
    else
        std::cout << "YEAH! That Euler was a LAMER!" << std::endl;

    std::cout << std::endl;
}

Еще один пример: решение квадратного уравнения над полем комплексных чисел.

char *input = "(-1,2) (-3, 5) (6,1)  (1,-2) (3, -5) (-6,-1)";
std::istrstream str(input);
Complex a, b, c, d, r1, r2;

while (true) {
    str >> a >> b >> c;
    if (!str)
        break;

    std::cout << "a = " << a << std::endl;
    std::cout << "b = " << b << std::endl;
    std::cout << "c = " << c << std::endl;
    std::cout << std::endl;

    if (a != 0) {
        d = sqrt(b * b - 4 * a * c);
        r1 = (-b + d) / (2 * a);
        r2 = (-b - d) / (2 * a);
        std::cout << r1 << std::endl;
        std::cout << r2 << std::endl;
    } else if (b != 0) {
        r1 = -c / b;
        std::cout << r1 << std::endl;
    } else if (c != 0)
        std::cout << "no roots" << std::endl;
    else
        std::cout << "infinitively many roots" << std::endl;
    std::cout << std::endl;
}