Смекни!
smekni.com

Программирование действий над матрицами на языке С++ (стр. 2 из 2)

Иногда возникает потребность описывать и применять к созданным программистом типам данных операции, по смыслу эквивалентные уже имеющимся в языке. Классический пример — библиотека для работы с комплексными числами. Они, как и обычные числовые типы, поддерживают арифметические операции, и естественным было бы создать для данного типа операции «плюс», «минус», «умножить», «разделить», обозначив их теми же самыми знаками операций, что и для других числовых типов. Запрет на использование определённых в языке элементов вынуждает создавать множество функций с именами вида ComplexPlusComplex, IntegerPlusComplex, ComplexMinusFloat и так далее.

Когда одинаковые по смыслу операции применяются к операндам различных типов, их вынужденно приходится называть по-разному. Невозможность применять для разных типов функции с одним именем приводит к необходимости выдумывать различные имена для одного и того же, что создаёт путаницу, а может и приводить к ошибкам. Например, в классическом языке Си существует два варианта стандартной библиотечной функции нахождения модуля числа: abs() и fabs() — первый предназначен для целого аргумента, второй — для вещественного. Такое положение, в сочетании со слабым контролем типов Си, может привести к труднообнаруживаемой ошибке: если программист напишет в вычислении abs(x), где x — вещественная переменная, то некоторые компиляторы без предупреждений сгенерируют код, который будет преобразовывать x к целому путём отбрасывания дробной части и вычислять модуль от полученного целого числа!

Отчасти проблема решается средствами объектного программирования — когда новые типы данных объявляются как классы, операции над ними могут быть оформлены как методы классов, в том числе и одноимённые (поскольку методы разных классов не обязаны иметь различные имена), но, во-первых, оформление подобным образом операций над значениями разных типов неудобно, а во-вторых, это не решает проблему создания новых операторов.

Средства, позволяющие расширять язык, дополнять его новыми операциями и синтаксическими конструкциями (а перегрузка операций является одним из таких средств, наряду с объектами, макрокомандами, функционалами, замыканиями) превращают его уже в метаязык — средство описания языков, ориентированных на конкретные задачи. С его помощью можно для каждой конкретной задачи построить языковое расширение, наиболее ей соответствующее, которое позволит описывать её решение в наиболее естественной, понятной и простой форме. Например, в приложении к перегрузке операций: создание библиотеки сложных математических типов (векторы, матрицы) и описание операций с ними в естественной, «математической» форме, создаёт «язык для векторных операций», в котором сложность вычислений скрыта, и возможно описывать решение задач в терминах векторных и матричных операций, концентрируясь на сути задачи, а не на технике. Именно из этих соображений подобные средства были в своё время включены в язык Алгол-68.

Чтобы разрешить существование нескольких одноимённых операций, достаточно ввести в язык правило, согласно которому операция (процедура, функция или оператор) опознаются компилятором не только по имени (обозначению), но и по типам их параметров. Таким образом, abs(i), где i объявлено как целое, и abs(x), где x объявлено как вещественное — это две разные операции. Принципиально в обеспечении именно такой трактовки нет никаких сложностей.

Чтобы дать возможность определять и переопределять операции, необходимо ввести в язык соответствующие синтаксические конструкции. Вариантов их может быть достаточно много, но по сути они ничем друг от друга не отличаются, достаточно помнить, что запись вида «<операнд1> <знакОперации> <операнд2>» принципиально аналогична вызову функции «<знакОперации>(<операнд1>,<операнд2>)». Достаточно разрешить программисту описывать поведение операторов в виде функций — и проблема описания решена.


2. Проектирование и этапы разработки

2.1 Постановка задачи

Задача заключается в создании динамического класса для работы с матрицами.

Чтение матриц происходит из файлов в котором они находятся, и после решений все полученные результаты выводятся в другой файл.

Интерфейс.

Интерфейс представлен примитивным меню в котором пользователь выбирает действие. При не открытии одного из файлов выводится ошибка, при успешное выполнение выводится сообщение об успехе.

2.2 Средства разработки

В качестве средства разработки выбран MSVisualStudio 2008 Express.

2.3 Описание процесса компиляции и запуска программы

Для компиляции программы используется IDEMSVisualStudio. В папке с проектом должны присутствовать файлы:file1.txt, file2.txt, file3.txt

Скомпиллированная программа состоит из следующих файлов:

1) папка cnf (конфигурационные файлы);

2) matrix.exe (исполняемый файл);


3. Реализация

3.1 Структура программы

Программа содержит компоненты, отвечающие за:

1) интерфейс,

2) математическую логику,

3) взаимодействие объектов класса,

4) перегрузку операторов.

3.2 Структура класса



Заключение

В ходе выполнения курсовой работы была получена работоспособная программа, удовлетворяющая начальному заданию.

В ходе разработке были проанализированы и использованы следующие технологии:

1) Stl;

2) потоков данных;

3) перегрузка операторов;

В качестве дальнейшего совершенствования программы представляется возможным увеличение функциональности класса и интерфейса (с целью увеличения информативности).


Литература

1. Свободная энциклопедия http://ru.wikipedia.org/

2. Книга У. Форд, У. Топп «Структура данных в С++» ООО «Бином-Пресс»2006г.

3. Беллман Р. Введение в теорию матриц. - М.: Мир, 1969.

4. Курош А.Г.Курс высшей алгебры: Учебник для вузов 15-е изд., стереотип. - М.: Лань, 2006. - 432 с.

5. Дж. Голуб, Ч. Ван Лоун Матричные вычисления. - М.: Мир, 1999.

6. Сайт «Знакомимся с вектором». http://www.cyberguru.ru/

7. Б. Страуструп. «Язык программирования C++. Специальное издание.», 2004 г.


Приложение. Исходный код программы. Заголовочные файлы.

1. matrix.h

#pragma once

#include <list>

#include <vector>

#include <iostream>

using std::vector;

using std::cout;

using std::istream;

using std::ostream;

class _matrix

{

private:

vector< vector<float> > vvf;

int stroka;

int stolbec;

public:

_matrix() {};

_matrix(int str, int stolb)

{

stroka = str;

stolbec = stolb;

vvf.resize(stroka, vector<float>(stolbec));

}

_matrix (const _matrix &obj)

{

stroka = obj.stroka;

stolbec = obj.stolbec;

vvf = obj.vvf;

}

~_matrix()

{

vvf.clear();

}

_matrix& operator+(_matrix &obj2)

{

_matrix* obj = new _matrix(*this);

for(int y = 0; y < obj2.stroka; y++)

for(int x = 0; x < obj2.stolbec; x++)

(*obj)(y, x) = (*this)(y, x) + obj2(y, x);

return *obj;

}

_matrix& operator-(_matrix &obj2)

{

_matrix* obj = new _matrix(*this);

for(int y = 0; y < obj2.stroka; y++)

for(int x = 0; x < obj2.stolbec; x++)

(*obj)(y, x) = (*this)(y, x) - obj2(y, x);

return *obj;

}

_matrix &operator*(_matrix &obj2)

{

_matrix* obj = new _matrix(*this);

for(int y = 0; y < obj->stroka; y++)

for(int x = 0; x < obj->stolbec; x++)

{

(*obj)(y, x) = 0;

for(int k = 0; k < obj->stroka; k++)

(*obj)(y, x) += obj2(k,x) * (*this)(y, k);

}

return *obj;

}

_matrix &operator=(const _matrix &obj)

{

stroka = obj.stroka;

stolbec = obj.stolbec;

vvf = obj.vvf;

return *this;

}

float &operator()(int& i, int& j)

{

return vvf[i][j];

}

_matrix &transpon()

{

_matrix transobj(*this);

for(int y = 0; y < stroka; y++)

for(int x = 0; x < stolbec; x++)

(*this)(y, x) = transobj(x, y);

return *this;

}

vector <float> multvec(int str, float value)

{

vector<float> temp(stroka);

for(int x = 0; x < stroka; x++)

{

temp[x] = value * vvf[str][x];

}

return temp;

}

void norm(int str, float value)

{

for(int x = 0; x < stroka; x++)

{

vvf[str][x] = vvf[str][x]/value;

}

}

void subvec(int str,vector<float> temp)

{

for(int x = 0; x < stroka; x++)

{

vvf[str][x] = vvf[str][x] - temp[x];

}

}

_matrix Inversion()

{

_matrix obj(*this);

_matrix invobj(stroka, stolbec);

float f;

for(int y = 0; y < stroka; y++)

invobj(y,y) = 1;

for(int x = 0; x < stolbec; x++)

{

for(int y = 1; y < stroka; y++)

{

if(x < y)

{

f =obj(y, x)/obj(x,x);

obj.subvec(y, obj.multvec(x, f));

invobj.subvec(y, invobj.multvec(x, f));

}

}

}

for(int x = stolbec-1; x > -1; x--)

{

for(int y = stroka-1; y > -1; y--)

{

f = obj(x,x);

obj.norm(x, f);//cout << obj;

invobj.norm(x, f);

if(x > y)

{

f =obj(y, x)/obj(x,x);

obj.subvec(y, obj.multvec(x, f));

invobj.subvec(y, invobj.multvec(x, f));

}

}

}

cout << obj;

cout << invobj;

return invobj;

}

friend ostream &operator<<(ostream &stream, _matrix &obj);

friend istream &operator>>(istream &stream, _matrix &obj);

};

ostream &operator<<(ostream &stream, _matrix &obj)

{

for(int y = 0; y < obj.stroka; y++)

{

for(int x = 0; x < obj.stolbec; x++)

{

stream << obj(y, x) << " ";

}

stream << "&bsol;n";

}

return stream;

}

istream &operator>>(istream &stream, _matrix &obj)

{

for(int y = 0; y < obj.stroka; y++)

for(int x = 0; x < obj.stolbec; x++)

stream >> obj(y, x);

return stream;

}


Приложение 2. Исходный код программы. Файлы cpp.

1. main.cpp

#include <iostream>

#include <conio.h>

#include <fstream>

#include "matrix.h"

using std::cout;

using std::ofstream;

using std::ifstream;

using std::cin;

using std::endl;

int primer1(_matrix &, _matrix &);

int primer2(_matrix &);

int primer1(_matrix &_objA, _matrix &_objB)

{

ofstream fout1;

_matrix _objC;

fout1.open("file3.txt");

if(!fout1)

{

cout << "Error with open output file" << endl;

exit(1);

}

_objC = _objA + _objB;

fout1 << "Сумма: &bsol;n";

fout1 << _objC;

_objC = _objA - _objB;

fout1 << "Разность: &bsol;n";

fout1 << _objC;

_objC = _objA * _objB;

fout1 << "Произведение: &bsol;n";

fout1 << _objC;

return 0;

}

int primer2(_matrix &_objA)

{

ofstream fout1;

fout1.open("file3.txt");

_matrix _objC;

if(!fout1)

{

cout << "nevozmojno open file3" << endl;

exit(1);

}

_objC = _objA.Inversion();

fout1 << "matrix Inversion &bsol;n";

fout1 << _objC;

_objC = _objA * _objC;

fout1 << "matrix * matrix.Inversion = &bsol;n";

fout1.precision(3);

fout1 << "%f" <<_objC;

return 0;

}

bool freadMatrix(_matrix& mtr, char* fileName)

{

ifstream fin;

fin.open(fileName);

if(!fin) return false;

fin>>mtr;

fin.close();

return true;

}

int menu()

{

int primer;

_matrix objA(5, 5);

_matrix objB(5, 5);

//чтение файлов

if(!freadMatrix(objA, "file1.txt") || !freadMatrix(objB, "file2.txt"))

{

cout << "Error with open input file" << endl;

return 1;

}

cout << "select action &bsol;n 1. + - * matrix &bsol;n 2. seatch Inversion matrix" << endl;

cin >> primer;

switch(primer)

{

case(1):

primer1(objA, objB);

break;

case(2):

primer2(objA);

break;

}

cout << "ok";

return 0;

}

int main(int argc, char** argv)

{

menu();

_getch();

return 0;

}