Ниже приводится код структуры и двух классов, над которыми

advertisement
Ниже приводится код структуры и двух классов, над которыми мы работали. В качестве задания
создайте консольные приложения, которые тестируют структуру 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;
}
}
}
Download