Программа 53. Комплексные числа
В данной программе приводятся дополнительные примеры использования перегрузки операторов.
Назовем модуль для класса комплексных чисел UnComplex. В файле
UnComplex.h разместим объявление класса комплексных чисел:
// Файл UnComplex.h
#ifndef UnComplexH
#define UnComplexH
#include <math.h>
class Complex
{ // Данные класса
double re, im; // Действительная и мнимая части комплексного числа
public: // Методы класса
Complex() // Конструктор по умолчанию
{ re = 0; im = 0; }
Complex(double x) // Конструктор с одним аргументом, формирование
{ re = x; im = 0; } // комплексного числа по одному вещественному
Complex(double x, double y) // Конструктор с двумя аргументами
{ re = x; im = y; }
double Arg(); // Аргумент комплексного числа
double Abs(); // Модуль комплексного числа
Complex& operator+=(Complex z) // Сложение с присваиванием
{
re += z.re; im += z.im; return *this;
}
Complex& operator-=(Complex z) // Вычитание с присваиванием
{
re -= z.re; im -= z.im; return *this;
}
Complex operator*(Complex); // Перемножение комплексных чисел
Complex operator*(double);// Умножение комплексного на вещественное
Complex operator/(Complex); // Деление комплексных чисел
Complex operator-(); // Унарный минус
void Roots(int m, Complex* rts); // Извлечение корней степени m
void Print(); // Вывод комплексного числа
};
// Объявление функций, не являющихся членами класса Complex
Complex operator+(Complex z, Complex t); // Сложение
Complex operator-(Complex z, Complex t); // Вычитание
Complex operator*(double a, Complex z); // Умножение
Complex Pow(Complex z, int m); //Возведение комплексного в степень m
// Получение комплексного числа по его модулю и аргументу
Complex Polar(double mod, double arg);
#endif
В классе Complex предусмотрены три конструктора, чтобы можно было создавать комплексные числа любым из следующих способов:
Complex z1(1, 2); // z1.re = 1, z1.im = 2
Complex z2(1); // z2.re = 1, z2.im = 0
Complex z3; // z3.re = 0, z3.im = 0
Наличие конструктора позволяет инициализировать комплексные числа при их определении:
Complex z4 = 13; // z4.re = 13, z4.im = 0
Здесь сначала создается безымянное комплексное число Complex(13) с использованием конструктора, которое затем используется для инициализации переменной z4.
Реализацию функций для работы с комплексными числами разместим в файле UnComplex.cpp.
// Файл UnComplex.cpp
#include "UnComplex.h"
#include <iostream.h>
// Функции-члены класса Complex
double Complex::Arg() // Аргумент комплексного числа
{ return atan2(im, re); }
Функция математической библиотеки (заголовочный файл math.h)
double atan2(double y, double x);
возвращает значение arctg(y/x). Она работает корректно, даже когда угол близок к π/2 или -π/2 (x близко к 0).
double Complex :: Abs() // Модуль комплексного числа
{ return sqrt(re * re + im * im); }
Complex Complex :: operator*(Complex z) // Умножение двух комплексных
{
Complex t(re * z.re - im * z.im, re * z.im + im * z.re);
return t;
}
Так как функция умножения является членом класса, ей доступно комплексное число, для которого она вызывается. Это число, представленное re и im, рассматривается как первый сомножитель. Второй сомножитель z передается в функцию как аргумент.
В следующей функции число с плавающей точкой a преобразуется в комплексное число конструктором, а затем используется функция умножения двух комплексных:
Complex Complex :: operator*(double a) // Умножение на double
{
return *this * Complex(a);
}
В функции деления реализованы обычные формулы деления комплексных чисел:
Complex Complex :: operator/(Complex z) // Деление
{
double r = (re * z.re +im * z.im) / (z.re * z.re + z.im * z.im);
double i = (-re * z.im + im * z.re) / (z.re * z.re + z.im * z.im);
return Complex(r, i);
}
Функция получения противоположного по знаку комплексного числа реализована как функция-член без аргументов:
Complex Complex :: operator-() // Унарный минус,
{ // получение комплексного числа
return Complex(-re, -im); // с противоположным знаком
}
Напомним, что комплексное число можно представить в алгебраической, показательной или тригонометрической форме:
.
Здесь x – действительная часть, y – мнимая часть, ρ – модуль комплексного числа, φ – аргумент. Корень степени m находится по формуле:
Функция Roots находит все корни m-й степени из комплексного числа и заносит их в массив rts
void Complex::Roots(int m, Complex rts[]) // Извлечение корней
{ // степени m
double angle = Arg(); // Аргумент
double mod = Abs(); // Модуль
mod = pow(mod, 1.0 / m); // Корень m-й степени из модуля
for(int k = 0; k < m; k++) // Получение m корней
rts[k] = Polar(mod, (angle + 2 * k * M_PI) / m);
}
void Complex::Print() // Функция вывода комплексного числа
{ cout << "(" << re << ", " << im << ")"; }
Функции, не являющиеся членами класса, используют функции-члены для доступа к закрытому представлению комплексного числа.
Complex operator+(Complex z, Complex t) // Сложение
{ return z += t; }
Для реализации сложения двух комплексных использован перегруженный оператор +=, аналогично, для реализации вычитания используется оператор -=.
Complex operator-(Complex z, Complex t) // Вычитание
{ return z -= t; }
//Умножение вещественного на комплексное
Complex operator*(double a, Complex z)
{
return z * a; // Умножение комплексного на double
}
В данной функции используется определенный ранее оператор умножения комплексного числа на действителное.
Следующая функция обеспечивает получение комплексного числа по его модулю и аргументу:
Complex Polar(double mod, double arg)
{ return Complex(mod * cos(arg), mod * sin(arg)); }
Целую степень комплексного числа можно найти по формуле:
.
Функция Pow реализует эту формулу.
Complex Pow(Complex z, int m) // Возведение комплексного числа
{ // в степень m
double angle = z.Arg(); // Аргумент
double mod = z.Abs(); // Модуль
angle *= m; // Увеличение аргумента в m раз
double mp = 1.0; // m-я степень модуля
for(int k = 0; k < m; k++) // находится с помощью
mp *= mod; // произведения
return Polar(mp, angle);
}
В качестве примера использования класса комплексных чисел решим приведенное кубическое уравнение:
.
Его корни можно выразить формулой Кардано:
.
Решение уравнения дают такие комбинации кубических корней, произведение которых равно –p/3.
Функцию main поместим в файле UnMainComplex.cpp.
#include ”UnComplex.h”
#include <iostream.h>
#include <conio.h>
#include "Rus.h"
int main()
{
const double eps = 0.1E-4; // Малое число (точность)
double x, y;
cout << Rus("Решаем приведенное кубическое уравнение \n”
” z^3 + p*z + q = 0\n");
cout << Rus("Введите действительную и мнимую части p: ");
cin >> x >> y;
Complex p(x, y); // Создание коэффициента p
cout << Rus("Введите действительную и мнимую части q: ");
cin >> x >> y;
Complex q(x, y); // Создание коэффициента q
Complex inner[2]; // Массив для квадратных корней
// Массивы для первого и второго кубического корня
Complex root3_1[3], root3_2[3];
Complex D; // Дискриминант кубического уравнения
D = q * q / 4 + p * p * p / 27;
D.Roots(2, inner); // Квадратный корень из дискриминанта
// Первое выражение под куб. корнем
Complex D1 = (-0.5) * q + inner[0];
// Второе выражение под куб. корнем
Complex D2 = (-0.5) * q - inner[0];
D1.Roots(3, root3_1); // Извлечение первого кубического корня
D2.Roots(3, root3_2); // Извлечение второго кубического корня
Complex p3 = -p / 3; // Критерий для отбора корней
Complex eq; // Левая часть уравнения
Complex z; // Переменная для корня
Complex prod; // Произведение кубических корней
// Перебор возможных комбинаций кубических корней
for(int i = 0; i < 3; i++) // Перебор значений первого кубич. корня
for(int j = 0; j < 3; j++){ // Перебор значений второго кубич. корня
prod = root3_1[i] * root3_2[j]; //Произведение кубических корней
double err = (prod - p3).Abs(); //Отклонение произведения от -p/3
if( err < eps){ //Если отклонение мало,
z = root3_1[i] + root3_2[j]; //это корень
cout << Rus("\nКорень z = "); z.Print();
eq = Pow(z, 3) + p * z + q; //Подстановка корня в уравнение
cout << Rus("\nПроверка: z^3 + p*z + q = "); eq.Print();
}
}
getch();
return 0;
}
В качестве примера решим уравнение
,
имеющее корни:
.
Далее приводится диалог с программой.
Решаем приведенное кубическое уравнение
z^3 + p*z + q = 0
Введите действительную и мнимую части p: -2 0
Введите действительную и мнимую части q: 1 0
Корень z = (1, 0)
Проверка: z^3 + p*z + q = (0, 0)
Корень z = (-1.61803, 1.94289e-16)
Проверка: z^3 + p*z + q = (0, 1.13739e-15)
Корень z = (0.618034, 0)
Проверка: z^3 + p*z + q = (0, 0)