Реферат: Организация математических операций в С++

МИНИСТЕРСТВО      ОБРАЗОВАНИЯ        УКРАИНЫ

З а п о р о ж с к и й     г о с у д а р с тв е н н ы й     т е х н и ч е с к и й    

у н и в е р с и т е т


/> <td/>

радиотехники

   

                                                               Кафедра __________________________


 ПОЯСНИТЕЛЬНАЯЗАПИСКА К  КУРСОВОМУ ПРОЭКТУ

                                    Объектно-ориентированное программирование

     Библиотечные способы для решения задач линейной алгебры

   ПО ДИСЦИПЛИНЕ ________________________________________________________________________________________________

________________________________________________________


 Розработала                                                                       

ст. гр.    РПз-538                                                             Крыгина А. А.                                                            


Принялпреподаватель                                                                   Пинчук  В.П.

2001р.

РЕФЕРАТ

ПЗ:       стр.

ЦЕЛЬ РАБОТЫ: разработатьбиблиотечные средства решения задач линейной алгебры.

ОБЪЕКТ ИССЛЕДОВАНИЯ:классовые типы – численная квадратная матрица и одномерный динамический массивс переменными размерами.

МЕТОД ИССЛЕДОВАНИЯ:разработка алгоритмов и написание классов функций на языке BorlandС++.

В курсовом проектеразработаны алгоритмы для решения основных задач линейной алгебры. По этималгоритмам на языке Borland C++ написаны два класса функций,ориентированных на объекты типа численная квадратная матрица и одномерныймассив (вектор). В классы включены арифметические операции, операцииввода-вывода, функции вычисления определителя матрицы, длины вектора, а такжерешения системы линейных алгебраических уравнений. Для наглядности полученныхрезультатов разработана демонстрационно-тестирующая программа.

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

         Список ключевыхслов:

 ЛИНЕЙНАЯ АЛГЕБРА, МАТРИЦА,ВЕКТОР, СИСТЕМА ЛИНЕЙНЫХ УРАВНЕНИЙ, ОПРЕДЕЛИТЕЛЬ, ФУНКЦИЯ, КЛАСС ФУНКЦИЙ,ОБЪЕКТ, ОПЕРАЦИЯ, ШАБЛОН, ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ.


 ВВЕДЕНИЕ

Объектно-ориентированноепрограммирование – это новый способ подхода к программированию. Такоепрограммирование, взяв лучшие черты структурного программирования, дополняетего новыми идеями, которые переводят в новое качество подход к созданиюпрограмм.

Наиболее важное понятиеязыков объектно-ориентированного программирования – это понятие объекта (object).Объект – это логическая единица, которая содержит данные и правила (методы)обработки этих данных. В языке С++ в качестве таких правил обработки выступаютфункции, т. е. объект в Borland C++ объединяет в себе данные ифункции, обрабатывающие эти данные.

Одним из самых главныхпонятий языка С++ является понятие класса (class). В языкеС++ для того, чтобы определить объект, надо сначала определить его форму спомощью ключевого слова class [1].

Ближайшей аналогией классаявляется структура. Память выделяется объекту только тогда, когда классиспользуется для его создания. Этот процесс называется созданием экземпляракласса (class instance).

Любой объект языка С++ имеетодинаковые атрибуты и функциональность с другими объектами того же класса. Засоздание своих классов и поведение объектов этих классов полную ответственностьнесет сам программист. Работая в некоторой среде, программист получает доступ кобширным библиотекам стандартных классов.

Обычно, объект находится внекотором уникальном состоянии, определяемом текущими значениями его атрибутов.Функциональность объектного класса определяется возможными операциями надэкземпляром этого класса.

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

template <список шаблонных типов> {объявление} ;

Различают шаблоны функций ишаблоны классов.

Шаблон классов задает образецопределений семейства классов. Над типизированными элементами этого классавыполняются одинаковые базовые операции вне зависимости от конкретного типаэлементов [2].


Введениев объектно-ориентированное программирование

Объектно-ориентированноепрограммирование представляет собой чуть более автоматизированный способпрограммирования. Объектно-ориентированные программы – это не простопроцедурные программы, переведенные на новый синтаксис. Они должны строится нановой философии разработки. Для них требуется новая стратегия программирования,которую часто бывает трудно освоить [3].

Основная идея ООП: программа состоит из группы объектов, часто связанных между собой. В С++объекты описываются при помощи нового типа данных class. Класс включает в себя набор переменных (данных) иопераций (методов или функций-членов), которые действуют на эти переменные.Полученными объектами можно управлять при помощи сообщений.

В ООП объекты включают всебя не только данные (данные-члены), но и методы (функции-члены) воздействияна эти данные. Эти две части в сочетании образуют функциональную единицупрограммы. Другими словами, объекты содержат данные и методы работы с этимиданными. Ниже приведены три основных преимущества объектно-ориентированныхпрограмм по сравнению с эквивалентными программами, разработанными сверху вниз.

·    Сопровождениепрограммы. Программыпроще читать и понимать, ООП позволяет управлять сложностью программы, оставляявидимыми программисту только существенные детали.

·    Модификацияпрограммы (добавление или исключение возможностей). Вы можете часто делать дополнения илиисключения в программе, например при работе с базой данных, просто добавляя иисключая объекты.  Новые объекты могут наследовать все свойства базовыхобъектов, необходимо только добавить или убрать отличающиеся свойства.

·    Повторноеиспользование. Можносохранить грамотно разработанный объект в наборе полезных программ и затемвставить его в новую программу с небольшими изменениями или без изменений.

 

ООП полностью принадлежитк миру С++, поскольку в С нет основного ядра – абстрактного типа данных class[5]. Поэтому переписатьпроцедурно-ориентированную программу как объектно-ориентированную гораздосложнее, чем просто подставить вместо одного ключевого слова другое.

ООП представляет собой техникупрограммирования, которая позволяет рассматривать основные идеи как множествообъектов. Используя объекты, можно представить задачи, которые необходимовыполнить, их взаимодействие  и любые заданные условия, которые должны бытьсоблюдены. Структура данных часто образует основы объектов; таким образом в Сили С++ тип structможетобразовывать элементарный объект. Связь с объектом можно организовать припомощи сообщений. Использование сообщений похоже на вызов функций впроцедурно-ориентированной программе. Когда объект получает сообщение, вступаютв действие методы, содержащиеся в объекте. Методы  (их иногда называют фунциями-членами)аналогичны функциям процедурно-ориентированного программирования. Тем не менееметод является частью объекта,  а не чем-то отдельным,  как было бы впроцедурном аналоге.

/>Основныетермины и положения ООП/>Инкапсуляция данных

Этот термин включает всебя логическое связывание данных с конкретной операцией. Она так же означает,что они являются не -глобальными доступными всей программе, а локальными –доступными только малой ее части. Инкапсуляция также автоматическиподразумевает защиту данных. Именно для этого предназначена структура class в С++. В классе управлениефункциональными деталями объекта осуществляется при помощи спецификаторов private, public, protected.

/>Иерархия классов

В общем случаеможно представить себе иерархию классов как родословную в генеалогическомдреве, где класс С++ представляет собой шаблон для создания классов-потомков.Объекты, полученные из описания класса, называют экземплярами этого класса.Можно создать иерархию классов  с классом-родителем и несколькимиклассами-потомками. Основой для этого являются  производные классы.

Наследование

          Наследование в ООП позволяетклассу получать совйства другого класса объектов. Родительский класс служитшаблоном для производного класса; этот шаблон можно менять различнымиспособами. Наследование является важным положением, поскольку оно позволяетповторно использовать определение класса без значительных изменений в коде.

Полиморфизм

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

Виртуальные функции

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

          Конструктор вызываетсякаждый раз, когда создается объект его класса. Задача конструктора в данномслучае состоит в связывании виртуальной функции с таблицей адресной информации.Во время компиляции адрес виртуальной функции неизвестен; вместо этого ейотводится позиция в таблице адресов. Эта позиция будет содержать адрес функции [5].


Глава 2.  Задачи линейной алгебры

2.1. Вычисление определителей

      Пусть имеем квадратную матрицу размером  n´n:

/>     .                                    (2.1.1)

Требуется вычислить определитель матрицы  det(A).

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

      Используя такого рода преобразования можно попытаться привестиис-ходную матрицу к треугольному виду:

/>      ,

при этом  det(A) = det(A¢).

      Формуладля пересчета элементов матрицы имеет вид:

/>  ,                                (2.1.2)

где    i         -  номер столбца, в котором элементы, лежащие нижеглавной
                        диагонали,превращаются в нули;

j         -  номер элемента в обрабатываемом столбце(т.е. номер строки);

k        - номер элемента в текущей строке.

      Алгоритмприведения матрицы к треугольному виду включает в себя 3 вложенных цикла:

-  внешний цикл,  i = 1… n-1;

          -  средний цикл,   j= i+1… n ;

          -  внутренний цикл,  k=  i+1… n.

      Теперь искомыйопределитель вычисляется как произведение диагональ-ных элементов:

                                   />.

      Описанный вышеалгоритм дает результат не всегда. Если при выполне-нии i-того шага внешнего цикла диагональный элемент aii оказываетсярав-ным нулю, а среди элементов i-того столбца сномерами от i+1 доn есть хотя бы один не нулевой, алгоритм завершаетсябезрезультатно (из-за невозмож-ности вычислений по формуле (2.1.2). Длятого, чтобы это не происходило, используется прием, который называется «выборглавного элемента».

      При выполнении очередного шага цикла по i предварительно выполняют-ся следующие операции:

          1)  находится максимальный по модулюэлемент среди элементов i-то-го столбца от aii до ani ;

          2)  если найденный элемент ali равеннулю, процесс вычисления завер-шается с выдачей результата  det(A)= 0 ;

          3)  если  l¹i, тогда строки исходной матрицыс номерами  i,l  поменятьместами.

      После завершения преобразования матрицы,определитель вычисляется по формуле:

                                             />  ,

где p – число выполненных операций перемены строкместами.

2.2  Обращение матриц

      Обратной к матрице Aназывается матрица A-1, обладающая свойством:

 A×A-1  =  A-1×A  =  I  ,

где  I – единичная диагональная матрица. Опишем один изуниверсальных и эффективных методов расчета обратной матрицы (методЖордана-Гаусса, в книге [4-218] описан как «метод исключений»). В [5-22] приведенболее эф-фективный по памяти алгоритм обращения матрицы.

      Пусть имеем матрицу Aвида (2.1.1) и пусть B –единичная диагональная матрица такого же размера. Создадим рабочую матрицу R размеромN´2N просто присоединив матрицу B справа к матрице A :

                             />  .

      Над строками такой расширенной матрицы будемпроизводить преобра-зования, аналогичные тем, которые были описаны в п.2.1.Левую часть мат-рицы R будем называть подматрицей A, правую – подматрицей B. Весь про-цесс преобразования матрицы R разобьемна 3 этапа.

      1 этап. Выполним преобразования строк матрицытак, чтобы все элемен-ты, лежащие ниже диагональных элементов подматрицы A,обратились в ну-ли. При этомможет использоваться выбор главного элемента.

      2 этап. Выполним преобразования так, чтобы всеэлементы, лежащие вы-ше диагональных элементов подматрицы A, обратились в нули. Преобразо-вания надо выполнять в обратном порядке: состолбца номер n и до столбца номер 2.

      3 этап. Каждую строку расширенной матрицы R с номером i делим на ди-агональный элемент aii.

      После завершения процедуры подматрица A превращается в единичную диагональную матрицу, а подматрицаB будетравна искомой обратной мат-рице A-1 .  Алгоритм имеет порядок  O(n3).

     

2.3.  Методы решения систем линейныхуравнений

      Задача поиска решений системы линейныхуравнений имеет не только са-мостоятельное значение, но часто являетсясоставной частью алгоритма ре-шения многих нелинейных задач. Основные методы решения СЛУ:

-  метод Гаусса;

-  метод обращения матрицы;

-  итерационные методы.

2.4.  Метод Гаусса

      Пусть имеем систему линейных уравнений:

                                      />

      Простой метод Гаусса состоит в следующем.

      Составим расширенную матрицу, приписав к матрице коэффициентовСЛУ дополнительный столбец – правые части уравнения:

                                                /> .

      Выполним над строками расширенной матрицы преобразования,анало-гичные тем, которые были описаны в п. 2.1:

      /> ,

       /> ,

и приведем ее к треугольному виду:

                                                />  .

      Теперь можно вычислить искомые величины xi,начиная с последнего, т.е. вначале находится xn, затем xn-1, xn-2, …, x1.Формула для вычислений имеет вид:

                                      />  .

      Для расширениявозможностей и повышения устойчивости приведенного алгоритма используется выборглавного элемента. Порядок метода Гаусса равен  O(n3).

     

2.5.  Метод обращения матрицы

      Представимсистему линейных уравнений в матричной форме:

     /> .

Умножим последнее равенство слева на  A-1 :

                                            /> .

Учитывая, что  A-1×A =  I,формально получаем искомое решение:

                                                   />

      Таким образом, решение системы выполняется вдва этапа:

   1)  вычисление обратной матрицы;

   2)  умножение обратной матрицы на вектор правыхчастей СЛУ.

      Несмотря на то, что метод обращения матрицыимеет такой же порядок, как и метод Гаусса — O(n3), по объему вычислений он проигрывает ему в нес-колькораз. Однако, если СЛУ необходимо решать многократно и при этом изменяется лишьвектор правых частей, метод обращения матрицы становит-ся все же выгодным.


Практическая часть

 

Описание класса Matrix для решения задач линейнойалгебры

 

Класс имеет приватные и общедоступные члены-данные ичлены-функции (методы). Для хранения компонентов матрицы используетсяодномерный динамический массив элементов типа параметра шаблона. Для созданияобъекта предусмотрены три конструктора: конструктор по умолчанию, конструктор спараметрами, конструктор копирования и деструктор. Для выполнения множестваматричных операций созданы перегруженные операции: присваивания (=), сложения(+), вычитания (-), умножения(*) и т.п. На базе операторов ввода/вывода С++разработаны функции ввода матриц из потока и вывода их в поток,предусматривающие в случае файлового ввода/вывода как текстовую форму хранения,так и бинарную.

Доступ к членам-данным класса – числу строк и столбцовматрицы осуществляется с помощью методов size_row( ) и size_col( ).Для доступа к элементам матрицы создан перегруженный оператор вызова функцииoperator( ) (dim x, dim x), где dim – переопределенный тип unsigned char.Вызов функции используется как оператор индексирования, принимающий двааргумента. Аналогично создан оператор вызова функции с одним аргументомoperator( ) (dim x). Для данного класса – это очень важные перегруженныеоператоры, т.к. они используются во всех функциях и операторах, в которыхпроисходит обращение к элементам матрицы.

Описание функций, конструкторов и деструкторов класса:

1.  Конструктор по умолчаниюMatrix( ):

Конструктор по умолчанию создает матрицу нулевогоразмера. В дальнейшем размер этой матрицы можно изменить с помощью функцииnewsize(i, j).

2.  Конструктор с параметрамиMatrix(dim, dim=1):

Это обычный конструктор с параметрами, которыйпринимает в качестве параметров размеры матрицы и создает одномерныйдинамический массив размером m*n, где m – число строк, а n – число столбцовматрицы. С целью возможности использовать его для создания векторов, второйпараметр конструктора задан как умалчиваемый со значением 1. Для первоначальной«инициализации» элементов матрицы нулями используется функция setmem( ).

3.  Конструктор копированияMatrix(const Matrix &):

Конструктор принимает в качестве параметра ссылку наобъект класса (на существующую матрицу), определяет ее размер, выделяет для неепамять и копирует в эту память содержимое матрицы, принимаемой по ссылке. Такимобразом, создается точная копия матрицы с текущими значениями ее элементов.

4.  Деструктор ~Matrix( ):

Деструктор высвобождает память, выделеннуюконструкторами для элементов матрицы.

5.  Функция операцииприсваивания "=" Matrix& operator= (Matrix&):

Данная функция сравнивает адрес передаваемого поссылке объекта с адресом собственного класса, чтобы не предпринялась попыткаприсвоит объект самому себе. После этого создается новый массив с числомэлементов, равным числу элементов массива принимаемого по ссылке, и в этотмассив заносится содержимое принимаемого массива. Возвращается разыменованныйуказатель this (return *this;).

6.  Функции операцийсуммирования, вычитания, умножения матриц и умножения матрицы на число:

Эти функции реализованы как дружественные функции иалгоритмы этих функций аналогичны по своему составу. Общий вид прототипа этихфункций: friend Matrix operator @(const Matrix&, constMatrix&). Применение дружественных функций в данном случае целесообразнодля того, чтобы иметь возможность передавать в оператор функцию объекты в любойпоследовательности. В этих операторах-функциях вначале создается временный объекттипа матрица (с помощью конструктора копирования), в который копируется перваяматрица и который при выходе из функции является возвращаемым объектом. Затемэта матрица суммируется (вычитается, умножается) с матрицей, стоящей послезнака оператора по соответствующим правилам матричных операций. При этом длядоступа к элементам матрицы и индексирования используются перегруженныеоператоры вызова функции operator( ) (dim x, dim x) иoperator( ) (dim x).

7.  Функция – оператор Matrixoperator^ (int):

Этот оператор-функция реализован как член класса ипредназначен для возведения матрицы в степень. В случае, когда значениевходного параметра равно минус единице осуществляется вызов функции вычисленияобратной матрицы методом преобразований Гаусса, для чего разработана отдельнаяфункция Matrix & Gauss(dim, dim). Таким образом, использованиеэтого оператора позволяет решать систему линейных алгебраических уравнений впредставлении X = (A^-1)*B, где X и B –вектора неизвестных и правых частейсоответственно.

8.  Функция – оператор Matrixoperator ! ( ):

Оператор для определения транспонированной матрицы.

9.  Функцияоператорfriend VARTYPE operator %(const Matrix&, constMatrix&):

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

10.      Функции-членыVARTYPE determ( ) иVARTYPE vmodule( ):

Первая функция вычисляет определитель собственногообъекта (матрицы). При этом используются функцияMatrix & Gauss(dim, dim). Функция VARTYPE vmodule( ) вычисляетдлину (модуль) вектора

11.      Функцияоперациивыводаfriend ostream&operator<<(ostream&, Matrix&):

Данная функция не может быть членом класса, поэтомучтобы иметь доступ к приватным элементам класса, она объявлена«дружественной» функцией. Она имеет два параметра: ссылку на поток,который находится слева от знака операции <<, и ссылку на объект, которыйнаходится слева от знака операции, данные этого объекта и будут выводиться.Затем следует форматированный вывод в поток всех элементов массива ивозвращается поток. Если требуется вывести данные в файл, нужно открыть его присоединениемк потоку ofstream.

12.       Функцияоперациивводаfriend istream&operator>>(istream&, Matrix&):

Так же как и предыдущая, данная функция не может бытьчленом класса, а поэтому для доступа к приватным элементам класса объявлена«дружественной» функцией класса. Она так же имеет два параметра:ссылку на поток, который находится слева от знака >>, и ссылку объект,который находится слева от знака операции, в него и будут вводиться данные изпотока. Затем следует ввод данных из потока в элементы массива и возвращаетсяпоток. Для ввода данных из файла, нужно открыть его присоединением к потокуifstream.

13.      Функции-членыdim write(ofstream&) иdim read(ifstream&):

Функции предназначены для вывода в файл и ввода изфайла матриц в из двоичном представлении. Для этого необходимо передать в нихсоответствующую ссылку на открытый файл.

14.      Функцияvoid ERROR_MATRIX(dim):

Это функция-член, которая вызывается для фиксациинекоторых ошибок при создании матриц и работе с ними, таких как отсутствиепамяти, несогласованность размеров матриц при операции умножения, попыткивычислить отрицательную степень матрицы и т.п.

 

 

Листинг модуля с определением иреализацией класса матриц

 

// файлtmatr.cpp

#include<stdlib.h>

#include<mem.h>    // для setmem()

#include<fstream.h>

#include<math.h>

typedef unsignedchar dim;

template <classVARTYPE> class Matrix {

typedef MatrixVector;

private:

   VARTYPE *matr;   //указатель на массив матрицы

   dim m,n;                   //размеры матрицы

public:

// конструкторы идеструкторы:

   Matrix() { matr=(VARTYPE*)0; m=n=0; }

   Matrix(dim,dim=1); // Обычный конструктор

   Matrix(constMatrix<VARTYPE>&); // Конструктор копирования

   ~Matrix() { delete [ ]matr; }

// доступ к элементам матрицы

   dim size_row() { return m; }            // число строк

   dim size_col(){ return n; }  // число столбцов

   VARTYPE&operator() (dim x) const { return (*this)(x,0); }        // элементу

// перегруженные операции ифункции:

   Matrix<VARTYPE>& operator=(constMatrix<VARTYPE>&);

  Matrix<VARTYPE>& operator=(const VARTYPE&);

  Matrix<VARTYPE> operator^(int);   // возведение в степень

  Matrix<VARTYPE> operator!();      // транспонирование

   VARTYPE determ();   // определитель матрицы

   VARTYPE vmodul();   //модуль вектора

   Matrix&Gauss(dim,dim); // преобразование по Гауссу

                                         // (для получ. обратной и единичной матрицы)

                                         // (для получ. верхнетреугольной матрицы)

   Matrix  minor(dim,dim); // возвращает указ. минор матрицы

   Vector  line(dim i)      // возвращает вектор-строку матрицы

               { return extract(1,n,i,0); }

   Vector  column(dim j)     // возвращает вектор-столбецматрицы

               { return extract(m,1,0,j); }

   VARTYPE&operator() (dim,dim) const;                                       // доступ к

Matrix<VARTYPE>&operator<<=(const Matrix &A) { return newsize(A.m,A.n)=A; }

                                                 //безусловное приравнивание матриц

  Matrix<VARTYPE>& insert(const Matrix&, dim=0, dim=0);       // вставить часть матрицы

  Matrix<VARTYPE> extract(dim, dim, dim=0, dim=0);                // извлечь часть матрицы

   Matrix<VARTYPE>& newsize(dim, dim=1);                                //установить новые размеры

   void swap_line(dim, dim);                                                               //обменстроками матрицы

   void swap_column(dim,dim);                                                         // обменстолбцами матрицы

   friend Matrix<VARTYPE> operator+(constMatrix<VARTYPE>&,const Matrix<VARTYPE>&);      //A-B

   friendMatrix<VARTYPE> operator-(const Matrix<VARTYPE>&,constMatrix<VARTYPE>&);       //A-B

   friendMatrix<VARTYPE> operator*(const Matrix<VARTYPE>&,constMatrix<VARTYPE>&);       //A*B

   friend Matrixoperator*(const double&,const Matrix<VARTYPE>&);  //k*A

   friend Matrixoperator*(const Matrix<VARTYPE>&, const double&); //A*k

   friendostream& operator<<(ostream&,Matrix<VARTYPE>&);

                                                 //потоковый вывод матрицы

   friend intoperator>>(istream&,Matrix<VARTYPE>&);

                                                 // потоковый ввод существ. матрицы

                                                 //0 — без. ошибок, 1 — была ошибка

   dim read(ifstream&);           // файловое чтение и запись матрицы

   dim write(ofstream&);         //в ее внутреннем, двоичном представлении.

   friend VARTYPE operator %(constMatrix<VARTYPE>&,const Matrix<VARTYPE>&);

   //Функция ошибок

   voidERROR_MATRIX(dim) const;

};

// Реализация класса матриц

template <classVARTYPE>

Matrix<VARTYPE>::Matrix(dimM, dim N)

 {

    m=M;

    n=N;

    matr=newVARTYPE[m*n];

    if(!matr)ERROR_MATRIX(1);

   setmem(matr,sizeof(VARTYPE)*m*n,0);

 }

template <classVARTYPE>

Matrix<VARTYPE>::Matrix(constMatrix<VARTYPE> &M_Obj)  //Конструктор копирования

 {

   m=M_Obj.m;

   n=M_Obj.n;

   matr=newVARTYPE[m*n];

   if(!matr)ERROR_MATRIX(1);

  movmem(M_Obj.matr, matr, sizeof(VARTYPE)*m*n);

 }

template <classVARTYPE>

Matrix<VARTYPE>&Matrix<VARTYPE>::operator=(const Matrix<VARTYPE> &M_Obj)

 {

   m=M_Obj.m;

   n=M_Obj.n;

   matr=newVARTYPE[m*n];

   if(!matr)ERROR_MATRIX(1);

  movmem(M_Obj.matr,matr,sizeof(VARTYPE)*m*n);

   return *this;

 }

//Диагональ?

template <classVARTYPE>

Matrix<VARTYPE>&Matrix<VARTYPE>::operator=(const VARTYPE &f)

 {

   for(inti=0,j;i<m;i++) for(j=0;j<n;j++)

      if(i==j)(*this)(i,j)=f;

      else(*this)(i,j)=0;

   return *this;

 }

template <classVARTYPE>

Matrix<VARTYPE>Matrix<VARTYPE>::operator^(int q) // Степень

 {

   if (q>0)

      {

             for(MatrixM=*this; q>1; q--)

              M=M*(*this);

             returnM;

      }

   if (q!=-1)ERROR_MATRIX(3);

   // вычисление обратной метoдом преобразований Гаусса

   if (n!=m)  ERROR_MATRIX(4);

   MatrixM(m,2*n);

  M.insert(*this);

   for(inti=0;i<M.m;i++)

     M(i,i+M.m)=1;

  for(i=0;i<M.m;i++)

     M.Gauss(i,i);

   returnM.extract(M.m,M.m,0,M.m);

 }

template <classVARTYPE>

Matrix<VARTYPE>Matrix<VARTYPE>::operator!()  //Транспозиция

 { Matrix<VARTYPE> A(n,m);

   for(int i=0, j;i<m; i++)

     for(j=0;j<n; j++)

      A(j,i)=(*this)(i,j);

   return A;

 }

template <classVARTYPE>

VARTYPEMatrix<VARTYPE>::determ() // рекурсивно находит определитель матрицы

 {

   if (n!=m)ERROR_MATRIX(4);

   if (n==1)

      return(*this)(0,0);

   for(int i=0;i<m; i++)

     if((*this)(i,0))

       {

             staticMatrix<VARTYPE> M;

             M<<= *this;

             VARTYPEd=M(i,0)*(i%2?-1:1);

             returnd*M.Gauss(i,0).minor(i,0).determ();

            }

   return 0.0;

 }

template <classVARTYPE>

VARTYPEMatrix<VARTYPE>::vmodul()      // Модуль вектора

 {

   VARTYPE d=0;

   if (n!=1)ERROR_MATRIX(9);

   staticMatrix<VARTYPE> M;

   M <<=*this;

   for(int i=0;i<m; i++)

     d=d+M(i,0)*M(i,0);

   return sqrt(d);

 }

template <classVARTYPE>

Matrix<VARTYPE>&Matrix<VARTYPE>::Gauss(dim M, dim N)

 {

  Matrix<VARTYPE>& A=*this;

   if (!A(M,N)) ERROR_MATRIX(5);

   for(inti=0,j;i<m;i++)

     for(j=0;j<n;j++)

            if(i!=M && j!=N)

             A(i,j)-=A(M,j)*A(i,N)/A(M,N);

  for(j=0;j<n;j++)

     if (j!=N)

             A(M,j)/=A(M,N);

  for(i=0;i<m;i++)

             A(i,N)=0;

   A(M,N)=1;

   return *this;

 }

template <classVARTYPE>

Matrix<VARTYPE>Matrix<VARTYPE>::minor(dim M, dim N)  // возвращ. матрицу без

 {                                                                                                         //строки y и столбца x

    Matrix<VARTYPE> A(m-1,n-1);

    for(inti=0,in=0,j,jn;i<m;i++)

      if (i!=M)

            {

              for(j=0,jn=0;j<n;j++)

                if (j!=N)

                  A(in,jn++)=(*this)(i,j);

              in++;

            }

   return A;

 }

template <classVARTYPE>   // вставка

Matrix<VARTYPE>&Matrix<VARTYPE>::insert(const Matrix<VARTYPE> &A, dim M, dim N)

 {

   if (M+A.m>m|| N+A.n>n)  ERROR_MATRIX(6);

   for(int i=0, j;i<A.m; i++)

     for(j=0;j<A.n; j++)

      (*this)(i+M,j+N)=A(i,j);

   return *this;

 }

template <classVARTYPE>   // извлечение

Matrix<VARTYPE>Matrix<VARTYPE>::extract(dim LM, dim LN, dim M, dim N)

 {

    if (M+LM>m|| N+LN>n)  ERROR_MATRIX(7);

   Matrix<VARTYPE> A(LM,LN);

    for(int i=0,j; i<LM; i++)

      for(j=0;j<LN; j++)

            A(i,j)=(*this)(i+M,j+N);

   return A;

 }

template <classVARTYPE>

VARTYPE&Matrix<VARTYPE>::operator() (dim M, dim N) const

 { return*(matr+n*M+N); }

template <classVARTYPE>

Matrix<VARTYPE>operator+(const Matrix<VARTYPE> &A, constMatrix<VARTYPE>&B)

 {

  Matrix<VARTYPE> C=A;

   for(int i=0,j;i<A.m; i++)

      for(j=0;j<A.n; j++)

             C(i,j)+=B(i,j);

   return C;

 }

template <classVARTYPE>

Matrix<VARTYPE>operator-(const Matrix<VARTYPE> &A, const Matrix<VARTYPE>&B)

 {

  Matrix<VARTYPE> C=A;

   for(int i=0, j;i<A.m; i++)

    for(j=0;j<A.n;j++)

      C(i,j)-=B(i,j);

   return C;

 }

template <classVARTYPE>

Matrix<VARTYPE>operator*(const Matrix<VARTYPE> &A,const Matrix<VARTYPE>&B)

{

 Matrix<VARTYPE> C(A.m,B.n);

  if (A.n!=B.m)

  {

    if(A.m==3 &&A.n==1 && B.m==3 && B.n==1)

    {

     C(0)=A(1)*B(2)-A(2)*B(1);

     C(1)=A(2)*B(0)-A(0)*B(2);

     C(2)=A(0)*B(1)-A(1)*B(0);

    }

    else

     A.ERROR_MATRIX(2);

  }

  else

  {

    for(inti=0,j,k;i<C.m;i++)

     for(j=0;j<C.n;j++)

            for(k=0;k<A.n;k++)

             C(i,j)+=A(i,k)*B(k,j);

  }

  return C;

}

template <classVARTYPE>//умножение числа на матрицу

Matrix<VARTYPE>operator*(const double &f,const Matrix<VARTYPE> &A)

 {

  Matrix<VARTYPE> B=A;

   for(inti=0,j;i<A.m;i++)

    for(j=0;j<A.n;j++)

       B(i,j)*=f;

   return B;

 }

template <classVARTYPE>// умножение матрицы на число

Matrix<VARTYPE>operator*(const Matrix<VARTYPE> &A, const double &f)

 {

  Matrix<VARTYPE> B=A;

   for(inti=0,j;i<A.m;i++)

    for(j=0;j<A.n;j++)

       B(i,j)*=f;

   return B;

 }

template <classVARTYPE>

Matrix<VARTYPE>&Matrix<VARTYPE>::newsize(dim M, dim N)

 { delete [] matr;

   m=M;

   n=N;

   if (N&& M) { matr=new VARTYPE[m*n];

   if (!matr)ERROR_MATRIX(1);

             setmem(matr,sizeof(VARTYPE)*m*n,0);}

    else { m=n=0; matr=(VARTYPE*)0;}

   return *this;

 }

template <classVARTYPE>

ostream&operator<<(ostream &out,Matrix<VARTYPE> &A)

 { for(inti=0,j;i<A.size_row();i++)

      {for(j=0;j<A.size_col();j++)

            out<< A(i,j)<< "  ";

            out<<endl;

      }

   return out;

 }

template <classVARTYPE>

intoperator>>(istream &inp,Matrix<VARTYPE> &A)

 { for(inti=0,j;i<A.size_row();i++)

     for(j=0;j<A.size_col();j++) if( !(inp>>A(i,j)) ) return 1;

   return 0;

 }

template <classVARTYPE>

voidMatrix<VARTYPE>::swap_line(dim L1, dim L2)

 {

   if (L1==L2)

     return;

   double b;

   for(intj=0;j<n;j++)

     {

      b=(*this)(L1,j);

      (*this)(L1,j)=(*this)(L2,j);

      (*this)(L2,j)=b;

     }

 }

template <classVARTYPE>

voidMatrix<VARTYPE>::swap_column(dim C1, dim C2)

 {

   if (C1==C2)

     return;

   double b;

   for(inti=0;i<m;i++)

    {

     b=(*this)(i,C1);

     (*this)(i,C1)=(*this)(i,C2);

     (*this)(i,C2)=b;

    }

 }

template <classVARTYPE>

dimMatrix<VARTYPE>::read(ifstream &finp)

 {(finp.get(m)).get(n); delete []matr; matr=new VARTYPE[m*n];

      if(!matr)ERROR_MATRIX(1);

  setmem(matr,sizeof(VARTYPE)*m*n,0);

   finp.read((char*)matr,sizeof(VARTYPE)*m*n); return finp.fail();

 }

template <classVARTYPE>

dimMatrix<VARTYPE>::write(ofstream &fout)

 { (fout.put(m)).put(n);

  (fout.write((char *)matr,sizeof(VARTYPE)*m*n))<<flush; returnfout.fail();

 }

template <classVARTYPE>

VARTYPEoperator%(const Matrix<VARTYPE> &A, constMatrix<VARTYPE>&B)

 {

   if(A.n!=1 ||B.n!=1) A.ERROR_MATRIX(9);

   if(A.m!=B.m)A.ERROR_MATRIX(0);

   VARTYPEscalarmul = 0;

   for(int i=0;i<A.m; i++)

             scalarmul= scalarmul+A(i)*B(i);

   returnscalarmul;

 }

template <classVARTYPE>

voidMatrix<VARTYPE>::ERROR_MATRIX(dim E) const

 { static char*message[] = {

             «Матрицы должны иметь одинаковуюразмерность»,                 //0

             «Невыделена память!»,                                                                   //1

             «Матрицы несогласованы для умножения»,                                //2

             «Степеньдолжна быть больше нуля или -1»,                                //3

             «Матрицадолжна быть квадратной»,                                            //4

             «Нулевойведущий элемент в преобразовании Гаусса»,             //5

             «Вставканевозможна из-за перекрытия базовой матрицы»,      //6

             «Извлекаемаяматрица выходит за границы базовой»,                //7

             «Выход заграницы. Попытка доступа к несущ. элементу»,       //8

             «Это невектор!»};                                                                            //9

   cerr<<«ERROR: „<< message[E]<< endl; exit(1);

 }


Демонстративно — тестирующаяпрограмма:

#include<conio.h>

#include<iostream.h>

#include<fstream.h>

#include“tmatr.cpp»

intmain()

{

 clrscr();

 Matrix<double> A(3,3), B(3,3), C(3,3);

 Matrix<double> V(3),X(3),H(3),U(3);

 double d;

 A(0,0)=1.1; A(0,1)=2.2; A(0,2)=3.3;

 A(1,0)=2.4; A(1,1)=1.1; A(1,2)=4.4;

 A(2,0)=1.3; A(2,1)=2.1; A(2,2)=4.1;

 B(0,0)=2; B(0,1)=7; B(0,2)=2;

 B(1,0)=4; B(1,1)=8; B(1,2)=1;

 B(2,0)=6; B(2,1)=4; B(2,2)=1;

 V(0)=2.1; V(1)=3.31; V(2)=1.4;

 H(0)=1.1; H(1)=2.1; H(2)=3.1;

//******************************

 C=A+B;

 cout<<«A:\n»<<A<<endl;

 cout<<«B:\n»<<B<<endl;

 cout<<«C=A+B:\n»<<C<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//******************************

  C=A-B;

 cout<<«A:\n»<<A<<endl;

 cout<<«B:\n»<<B<<endl;

 cout<<«C=A-B:\n»<<C<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//******************************

//******************************

 X=V+H;

 cout<<«V:\n»<<V<<endl;

 cout<<«H:\n»<<H<<endl;

 cout<<«X=V+H:\n»<<X<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//******************************

 X=V-H;

 cout<<«V:\n»<<V<<endl;

 cout<<«H:\n»<<H<<endl;

 cout<<«X=V-H:\n»<<X<<endl;

 cout<<«Press any key...\n»;

 getch();

  clrscr();

 C=A*V;

 cout<<«A:\n»<<A<<endl;

 cout<<«V:\n»<<V<<endl;

 cout<<«C=A*V:\n»<<C<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//******************************

 Matrix<int> D(3,3), E(3,3);

 D(0,0)=1; D(0,1)=2; D(0,2)=3;

 D(1,0)=2; D(1,1)=5; D(1,2)=6;

 D(2,0)=7; D(2,1)=3; D(2,2)=9;

 ofstream fout(«test.mtr»);

 if(!fout)

    {

     cout<<«file not open\n»;

     return 1;

    }

 D.write(fout);

 fout.close();

 ifstream fin(«test.mtr»);

 if(!fin)

    {

     cout<<«file not open\n»;

     return 1;

    }

 E.read(fin);  //é ñó«¿t¡«¼ó¿ñÑ

 cout<<«D:\n»;

 cout<<D;

 cout<<«E:\n»;

 cout<<E;

 fin.close();

 cout<<«Press any key...\n»;

 getch();

 clrscr();

 //************************************

 C=A^-1;

 cout<<«A:\n»<<A<<endl;

 cout<<«C=A^-1:\n»<<C<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

 //****************************

 //A*X=V   X=(A^-1)*V

 X=(A^-1)*V;

 cout<<«A^-1:\n»<<(A^-1)<<endl;

 cout<<«V:\n»<<V<<endl;

 cout<<«X:\n»<<X<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//************************************

 d=A.determ();

 cout<<«determinant of A = „<<d<< endl;

 d=V.vmodul();

 cout<<“modul of V = „<<d<< endl;

 cout<<“Press any key...\n»;

 getch();

 clrscr();

//************************************

 V(0)=4; V(1)=3; V(2)=2;

 U(0)=1; U(1)=2; U(2)=3;

 d=V%U;

 cout<<«scalar product V*U= „<< d<<endl;

 cout<<“Press any key...\n»;

 getch();

 clrscr();

//************************************

  C=!A;

 cout<<«A:\n»<<A<<endl;

 cout<<«C=!A:\n»<<C<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

 C=5*A;

 B=A*2;

 cout<<«A:\n»<<A<<endl;

 cout<<«C=5*A:\n»<<C<<endl;

 cout<<«B=A*2:\n»<<B<<endl;

 cout<<«Press any key...\n»;

 getch();

 clrscr();

//************************************

//************************************

return0;

Результаты тестирования класса Matrix

Сложениематриц A и B:

    A:                                                 B:                                            C=A+B:

1.1     2.2     3.3                        2        7        2                           3.1     9.2     5.3

2.4     1.1     4.4                        4        8        1                           6.4     9.1     5.4

1.3     2.1     4.1                        6        4        1                           7.3     6.1     5.1

Вычитаниематриц A и B:

    A:                                                 B:                                            C=A-B:

1.1     2.2     3.3                        2        7        2                           -0.9   -4.8   1.3

2.4     1.1     4.4                        4        8        1                           -1.6   -6.9   3.4

1.3     2.1     4.1                        6        4        1                           -4.7   -1.9   3.1

Сложениематриц A и B:

    A:                                                 B:                                            C=A*B:

1.1     2.2     3.3                        2        7        2                           30.8   38.5   7.7

2.4     1.1     4.4                        4        8        1                           35.6   43.2   10.3

1.3     2.1     4.1                        6        4        1                           35.6   42.3   8.8

Сложение векторов

V:

2.1

3.31

1.4

H:

1.1

2.1

3.1

X=V+H

3.2

5.41

4.5

Вычитание векторов

V:

2.1

3.31

1.4

H:

1.1

2.1

3.1

X=V-H:

1

1.21

-1.7

Умножение матрицы на вектор

A:

1.1  2.2  3.3

2.4  1.1  4.4

1.3  2.1  4.1

V:

2.1

3.31

1.4

C=A*V:

14.212

14.841

15.421

Запись матрицы в файл

D:

1 2  3

2 5  6

7 3  9

Считывание матрицы из файла

E:

1 2  3

2 5  6

7 3  9

Вычисление обратной матрицы

A:

1.1  2.2  3.3

2.4  1.1  4.4

1.3  2.1  4.1

C=A^-1:

2.009346 0.88785  -2.570093

1.750212 -0.093458  -1.308411

-1.53356 -0.233645  1.728972

Решение алгебраического уравнения

A^-1:

2.009346 0.88785  -2.570093

1.750212 -0.093458  -1.308411

-1.53356 -0.233645  1.728972

V:

2.1

3.31

1.4

X:

3.56028

1.534325

-1.57328

Определение детерминанта матрицы

determinant of A = -2.354

Определение длины (модуля) вектора

modul of V = 4.162463

Вычисление скалярного произведения векторов

scalar product V*U= 16

 


ВЫВОД

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

Классы написаны на языке С++, однако могут быть легкопереписаны на любом из современных языков программирования, так как приведеныдовольно простые алгоритмы всех компонентных функций. Были максимальнопредусмотрены все возможные ошибки, которые могут возникнуть при использованиифункций данных классов. Особое внимание уделялось разумному выделению памятипод объекты во время выполнения программы, поэтому все функции были тщательно отлажены.

Классы Matrixи Vector могут быть эффекивно применены напрактике в задачах, требующих операций с матрицами и векторами, а такжесвязанных с решением систем линейных алгебраических уравнений.


Списокиспользованной литературы

1.   Дискретная математика, конспектлекций. В. Г. Засовенко. Запорожье, 1998 г.

2.   Начальный курс С и С++. Б. И.Березин. Москва: «ДИАЛОГ-МИФИ», 1999 г.

3.   Язык программирования С++. Б.Страуструп. Киев:«ДиаСофт», 1993 г.

еще рефераты
Еще работы по информатике, программированию