Ниже приводится код структуры и двух классов, над которыми мы работали. В качестве задания создайте консольные приложения, которые тестируют структуру Complex и решение квадратного уравнения. 1. Структура Complex using System; using System.Text; using System.IO; namespace nsComplex { /// <summary> /// Представляет комплексное число как совокупность /// вещественной и мнимой частей в виде чисел с двойной точностью типа double /// </summary> public struct Complex : IFormattable { #region Fields /// <summary> /// Хранит мнимую единицу /// </summary> public static readonly Complex i = new Complex(0, 1); /// <summary> /// Хранит комплексный нуль /// </summary> public static readonly Complex Zero; /// <summary> /// Хранит текущее значение вещественной части /// </summary> private double re; /// <summary> /// Хранит текущее значение мнимой части /// </summary> double im; #endregion #region Properties /// <summary> /// Возвращает вещественную часть /// </summary> public double Re { get { return re; } } /// <summary> /// Возвращает мнимую часть /// </summary> public double Im { get { return im; } } /// <summary> /// Возвращает модуль /// </summary> public double Mod { get { return Math.Sqrt(re * re + im * im); } } /// <summary> /// Возвращает аргумент в интервале (-pi; pi] /// </summary> public double Arg { get { return Math.Atan2(im, re); } } #endregion #region Конструкторы /// <summary> /// Инициализирует поля структуры /// вещественную и мнимую часть комплексного числа /// </summary> /// <param name="Re"> /// Вещественная часть /// </param> /// <param name="Im"> /// Мнимая часть /// </param> public Complex(double re, double im) { this.re = re; this.im = im; } /// <summary> /// Создает комплексное число с заданным модулем и аргументом /// </summary> /// <param name="Mod"> /// Модуль /// </param> /// <param name="Arg"> /// Аргумент /// </param> /// <returns> /// Комплексное число /// </returns> /// <remarks> /// Вычисляет вещественную и мнимую части часть и вызывает конструктор. /// </remarks> static public Complex Create(double mod, double arg) { if (mod < 0) throw new ArgumentOutOfRangeException("Модуль комплексного числа не может быть отрицательным!"); if (mod == 0) return Complex.Zero; return new Complex(mod * Math.Cos(arg), mod * Math.Sin(arg)); } #endregion #region Комплексная арифметика. Переопределенные операторы /// <summary> /// Складывает два комплексных числа (бинарный плюс) /// </summary> static public Complex operator +(Complex c1, Complex c2) { return new Complex(c1.Re + c2.Re, c1.Im + c2.Im); } /// <summary> /// Возвращает комплексное число с обратным знаком (унарный минус) /// </summary> static public Complex operator -(Complex c) { return new Complex(-c.Re, -c.Im); } /// <summary> /// Вычитает два комплексных числа (бинарный минус) /// </summary> static public Complex operator -(Complex c1, Complex c2) { return c1 + (-c2); } /// <summary> /// Умножает два комплексных числа /// </summary> static public Complex operator *(Complex c1, Complex c2) { return new Complex(c1.Re * c2.Re - c1.Im * c2.Im, c1.Re * c2.Im + c1.Im * c2.Re); } /// <summary> /// Делит два комплексных числа /// </summary> static public Complex operator /(Complex c1, Complex c2) { double _mod = c2.Mod, mod_2 = 1 / _mod / _mod; return c1 * ~c2 * mod_2; } /// <summary> /// Преобразует комплексное число в сопряженное /// </summary> static public Complex operator ~(Complex c) { return new Complex(c.Re, -c.Im); } /// <summary> /// Неявно преобразует действительное число в комплексное. /// </summary> static public implicit operator Complex(double a) { return new Complex(a, 0); } // Операторы равенства/неравенства /// <summary> /// Определяет равенство двух комплексных чисел /// </summary> /// <returns> /// true, если числа равны, false в противном случае /// </returns> static public bool operator ==(Complex c1, Complex c2) { return c1.Re == c2.Re && c1.Im == c2.Im; } /// <summary> /// Определяет неравенство двух комплексных чисел /// </summary> /// <returns> /// true, если числа не равны, false в противном случае /// </returns> static public bool operator !=(Complex c1, Complex c2) { return !(c1 == c2); } #endregion #region Methods #region Переопределенные версии унаследованных виртуальных методов /// <summary> /// Проверяет равенство комплексных чисел /// </summary> /// <param name="obj"> /// Сравниваемое комплексное число /// </param> /// <returns> /// true, если текущее число совпадает с аргументом, false в противном случае /// </returns> public override bool Equals(object obj) { return obj != null && obj is Complex && (Complex)obj==this; } /// <summary> /// Сопоставляет каждому комплексному числу хэш-код - целое число. /// </summary> /// <returns> /// Хэш-код текущего числа /// </returns> public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } /// <summary> /// Формирует текстовое представление комплексного числа /// </summary> /// <returns> /// Строка, отвечающая текстовому представлению /// </returns> public override string ToString() { // Вызов реализации метода ToString с параметром-строкой форматирования return ToString("g"); } #endregion #region Собственные методы /// <summary> /// Определяет квадратный корень из комплексного числа с положительной вещественной частью /// </summary> /// <param name="c"> /// Аргумент /// </param> /// <returns> /// Квадратный корень из аргумента, имеющий положительную вещественную часть /// </returns> public static Complex Sqrt(Complex c) { return Complex.Create(Math.Sqrt(c.Mod), .5 * c.Arg); } /// <summary> /// Формирует текстовое представление комплексного числа в заданном формате /// </summary> /// <param name="format"> /// Строка формата /// </param> /// <returns> /// Строка, представляющая комплексное число в выбранном формате /// </returns> public string ToString(string format) { return ToString(format, null); // Вызов реализации ToString интерфейса IFormattable } #endregion #region Реализация метода унаследованного интерфейса IFormattable /// <summary> /// Форматирует значение текущего экземпляра с использованием заданного формата /// </summary> /// <param name="format"> /// Объект, задающий используемый формат /// </param> /// <param name="provider"> /// Объект, используемый для форматирования значения /// </param> /// <returns> /// Значение текущего экзмепляра в заданном формате /// </returns> /// <remarks> /// Реализация метода интерфейса IFormattable /// </remarks> public string ToString(string format, IFormatProvider formatProvider) { return re == 0 && im == 0 ? "0" : ((re != 0 ? re.ToString(format, formatProvider) : "") + (im == 0 ? "" : (im < 0 ? "-" : re == 0 ? "" : "+") + (Math.Abs(im) == 1 ? "" : Math.Abs(im).ToString(format, formatProvider)) + "i")); } #endregion #endregion /// <summary> /// Доопределяет метод Write для структуры Complex /// </summary> public class BinaryWriter : System.IO.BinaryWriter { /// <summary> /// Вызывает конструктор предка, не выполняя иных действий /// </summary> /// <param name="s"></param> public BinaryWriter(Stream s) : base(s) { } /// <summary> /// Посылает объект типа Complex в бинарном виде в поток /// </summary> /// <param name="c"> /// Значение комплексного числа, посылаемого в поток /// </param> public void Write(Complex c) { base.Write(c.Re); base.Write(c.Im); } } } } 2. Абстрактный класс решения уравнения степени n using System; using System.Text; using nsComplex; using System.IO; using System.Data; namespace nsPolynomEq { public abstract class PolynomEq { #region Members (члены класса) // Поля обычно имеют доступ private (доступны только внутри класса). // При отсутствии модификатора доступа у членов класса - доступ private #region Fields (поля класса) /// <summary> /// Хранит ссылку на объект класса _rnd, позволяющий генерировать случайные числа /// Поле инициализируется оператором new и вызовом конструктора класса Random() /// </summary> Random _rnd = new Random(); /// <summary> /// Хранит ссылку на массив коэффициентов уравнения. /// </summary> double[] _a; /// <summary> /// Хранит ссылку на массив корней уравнения. /// Поле инициализируется оператором new /// с созданием ссылки на массив из двух чисел типа double. /// </summary> Complex[] _x; /// <summary> /// Хранит ссылку на массив значений левой части уравнения /// после подстановки туда соответствуюих корней /// </summary> Complex[] _zero; #endregion // Свойства создаются для доступа к полям. #region Properties (свойства) /// <summary> /// Возвращает порядок полинома /// </summary> public int N { private set; get; } /// <summary> /// Возвращает ссылку на массив коэффициентов /// </summary> public double[] a { get { return _a; } } #endregion #region Indexer /// <summary> /// Возвращает решение с заданным индексом /// </summary> /// <param name="i"> /// Значение индекса /// </param> /// <returns> /// Решение или NaN, если решение не найдено /// </returns> public Complex this[int i] { get { return (_x == null ? Double.NaN : _x[i]); } } #endregion #region Ctr /// <summary> /// Инициализирует поля экземпляра /// </summary> /// <param name="n"> /// Порядок полинома уравнения /// </param> protected PolynomEq(int n) { if (n <= 1) throw new ArgumentException("Порядок полинома должен быть больше единицы!"); N = n; _a = new double[n]; _zero = new Complex[n]; } #endregion #region Methods (методы класса) /// <summary> /// Читает коэффициенты с консоли /// </summary> public void ReadCoeff() { // Ввод коэффициентов уравнения с консоли for (int i = 0; i < N; i++) { Console.Write( (i == 0 ? "Введите свободный член уравнения:{0}" : "Введите коэффициент перед {0}-ой степенью"), (i == 0 ? "" : i.ToString())); _a[i] = double.Parse(Console.ReadLine()); } } /// <summary> /// Задает коэффициенты случайными числами в интервале [-10;10) /// </summary> public void SetRandomCoeff() { // Инициализация коэффициентов случайными числами в интервале [-10;10) // (метод NextDouble() объекта _rnd) for (int i = 0; i < N; i++) _a[i] = 20 * _rnd.NextDouble() - 10; } /// <summary> /// Пишет результат в текстовой файл или на экран /// </summary> /// <param name="tw"> /// Объект, отвечающий текстовому файлу или экране /// </param> public void WriteResult(TextWriter tw) { // Вывод результатов на носитель, который сопоставлен объекту tw // (экран или текстовой файл) for (int i = 0; i < N; i++) { tw.WriteLine("{0} - й корень: {1} ", i + 1, _x[i]); tw.WriteLine("Левая часть уравнения для {0} - ого корня\n {1} ", i + 1, _zero[i]); } tw.Close(); } /// <summary> /// Заполняет таблицы базы данных /// </summary> /// <param name="ds"> /// База данных /// </param> public void WriteResult(DataSet ds) { // К таблице CoeffTable добавляется строка ds.Tables["CoeffTable"].Rows.Add(ds.Tables["CoeffTable"].NewRow()); // В элементы этой строки таблицы CoeffTable заносятся значения коэффициентов for (int i = 0; i < N; i++) ds.Tables["CoeffTable"].Rows[ds.Tables["CoeffTable"].Rows.Count 1][String.Format("a[{0}]", i)] = _a[i]; // К таблице XTable добавляются три строки, // в которые помещаются соответствующие корни for (int i = 0; i < N; i++) { ds.Tables[1].Rows.Add(ds.Tables[1].NewRow()); ds.Tables[1].Rows[ds.Tables[1].Rows.Count - 1]["X"] = _x[i]; } // К таблице ZeroTable добавляются три строки, // в которые помещаются соответствующие значения левой части уравнения for (int i = 0; i < N; i++) { ds.Tables[2].Rows.Add(ds.Tables[2].NewRow()); ds.Tables[2].Rows[ds.Tables[2].Rows.Count - 1]["Zero"] = _zero[i]; } } /// <summary> /// Отдает результаты в поток /// (сохраняет в бинарном файле или передает в сеть или в локальную память) /// </summary> /// <param name="s"> /// Поток вывода результатов /// </param> public void WriteResult(Stream s) { if (!s.CanWrite) { // Если в поток нельзя писать, то метод не выполняется Console.WriteLine( "Поток {0} не позволяет производить в него запись данных", s.ToString()); return; } try // Попытка записи в поток s { Complex.BinaryWriter bw = new Complex.BinaryWriter(s); for (int i = 0; i < N; i++) { bw.Write(_a[i]); bw.Write(_x[i]); bw.Write(_zero[i]); } } catch (Exception ex) { // Если при записи в поток s возникла исключительная ситуация, // управление будет передано в эту область Console.WriteLine(ex.Message); return; } } /// <summary> /// Метод поиска корней уравнения, реализуемый в наследниках /// </summary> /// <returns> /// Ссылку на массив корней уравнения порядка N /// </returns> protected abstract Complex[] GetRoots(); /// <summary> /// Решает уравнение x^N + a[N-1]*x^(N-1) +...+ a[1]*x + a[0] = 0 /// и определяет значения левых частей уравнения после подстановки в них значений найденных корней. /// </summary> public void Solve() { // Определение корней уравнения _x = GetRoots(); // Подсчет левых частей уравнения для найденных корней for (int i = 0; i < N; i++) { _zero[i] = _a[0]; Complex xPow = 1; for (int j = 1; j < N; j++) _zero[i] += _a[j] * (xPow *= _x[i]); _zero[i] += xPow * _x[i]; } } #endregion #endregion } } 3. Класс решения квадратного уравнения using System; using System.Text; using nsComplex; using nsPolynomEq; namespace nsQuadraticEquation { public class QuadraticEquation:PolynomEq { /// <summary> /// Конструктор. Инициализирует поля, вызывая конструктор базового класса. /// </summary> public QuadraticEquation() : base(2) { } /// <summary> /// Вычисляет корни квадратного уравнения /// </summary> /// <returns> /// Массив корней /// </returns> protected override Complex[] GetRoots() { Complex[] x = new Complex[2]; // Вычисляется корень из дискриминанта (не зависимо от его знака, т.к. корень комплексный) Complex sqrt = Complex.Sqrt(a[1] * a[1] - 4 * a[0]); // Вычисляются корни x[0] = -.5 * (a[1] + sqrt); x[1] = -.5 * (a[1] - sqrt); return x; } } }