Литература / Козин Р.Г. Алгоритмы численных методов линейной алгебры и их программная реализация
.pdf
Рис. 2.14. Экранная форма программы, на которой сформирована
0 |
2 |
3 |
обратная матрица для исходной матрицы 4 |
5 |
0 . Заметим, что если |
|
6 |
|
0 |
8 |
с помощью переключателя отключить процедурувыбора ведущего элемента, то определить обратную матрицуне удастся. Последнее подтверждает необходимость использования указанной процедуры
врассмотренных выше алгоритмах
Вкачестве примера приведем экранную форму (рис. 2.14) программы, написанной на языке C++ с использованием библиотеки Qt,
которая для введенной матрицы рассчитывает (использованы описанные выше алгоритмы) ее определитель и обратную матрицу. Пользователь последовательно задает размерность матрицы и вводит значения ее компонент или формирует ее случайным образом.
После нажатия управляющей кнопки «найти обратную матрицу» программа на месте исходной матрицы формирует рассчитан-
91
ную обратную матрицу. Одновременно выдается значение определителя исходной матрицы и число использованных перестановок столбцов.
Далее полученную матрицу можно протестировать, проверев выполнение соотношения A(обр)*А = E (рис. 2.15).
Рис. 2.15. Результаты тестирования полученной обратной матрицы
Ниже представлены листинги программ данного приложения, которые запускаются при нажатии кнопок «сформировать случайную матрицу», «найти обратную матрицу» и «тест ? – А(обр)*А = Е»:
// слот -> формируем случайную матрицу void MainWindow::on_pushButton_2_clicked()
{
int i,j; double num;
for (i=0; i<n;i++)
{
92
for (j=0; j<n;j++)
{
num=(double(rand())/RAND_MAX-0.5)*2; // формируем случайное число из диа-
пазона (-1,1)
QTableWidgetItem *item=new QTableWidgetItem; item->setText(QString("%1").arg(num)); ui->tableWidget->setItem(i,j,item);
}
}
ui->lineEdit->clear(); ui->lineEdit_2->clear();
//QMessageBox::information(0,tr("Сообщение"),tr("Готово")); ui->statusBar->showMessage(tr("!!! - СЛУЧАЙНАЯ МАТРИЦА СФОРМИРОВАНА -
!!!"),2000);
ui->pushButton->setEnabled(true); //делаем кнопку доступной ui->pushButton_3->setEnabled(false); //недоступной
n_n=0; fl_enb=1;
}
// нахождение обратной матрицы методом Гаусса-Жордана void MainWindow::on_pushButton_clicked()
{
int i,j,k,m0,m1,rang; det=1; m=0;rang=n;
for (i=0; i<n;i++) // Инициируем матрицу из таблицы
{
for (j=0; j<n;j++)
{
A[i][j]=ui->tableWidget->item(i,j)->text().toDouble(&ok); if (ok==false)
{
Int warn =QMessageBox::warning(0,tr("Предупреждение"), tr("Ошибка в задании компонента/ов матрицы"));
return;
}
B[i][j]=A[i][j]; //дублируем исходную матрицу
}
}
for (k=0;k<n;k++)
{
if (fl_check==1)
{
select_Amax(k); // выбор ведущего элемента
}
else
{
if (fabs(A[k][k])<pow(10,-30))
{
det=0;
93
int warn=QMessageBox::warning(0,tr("Предупреждение"), tr("У матрицы встре-
тился диагональный элемент < 10 E-30. Процесс нахождения обратной матрицы прерван!"));
return;
}
};
if (det==0) {rang=k;break;} for (i=0;i<n;i++)
{
if (i!=k)
{
A[i][k]=-A[i][k]/A[k][k]; for (j=0;j<n;j++)
{
if (j!=k)
{
A[i][j]=A[i][j]+A[i][k]*A[k][j];
}
}
}
}
for (j=0;j<n;j++)
{
if (j!=k)
{
A[k][j]=A[k][j]/A[k][k];
}
}
A[k][k]=1/A[k][k];
}
if (m>0) // переставлям строки
{
for (i=(m-1);i>=0;i--)
{
m0=L[0][i];
m1=L[1][i];
for (j=0;j<n;j++)
{
buf=A[m0][j];
A[m0][j]=A[m1][j];
A[m1][j]=buf;
}
}
}
ui->lineEdit->setText(QString("%1").arg(det)); ui->lineEdit_2->setText(QString("%1").arg(m)); ui->lineEdit_3->setText(QString("%1").arg(rang)); if (det!=0)
{
for (i=0; i<n;i++) // Вставляем обратную матрицу в таблицу
{
for (j=0; j<n;j++)
94
{
QTableWidgetItem *item=new QTableWidgetItem; item->setText(QString("%1").arg(A[i][j])); ui->tableWidget->setItem(i,j,item);
}
}
ui->pushButton_3->setEnabled(true); //делаем кнопку "тест.." доступной ui->statusBar->showMessage(tr("!!! - ОБРАТНАЯ МАТРИЦА НАЙДЕНА - !!!"),2000);
//текст отображается в течение 2 сек.
}
else
{
int warn=QMessageBox::warning(0,tr("Предупреждение"),tr("Матрица ВЫРОЖ-
ДЕННАЯ"));
}
}
// процедура выбора ведущего элемента void select_Amax(int k)
{
int i,kmax,j;
double Amod,Amax; if(k<(n-1))
{
Amax=fabs(A[k][k]); kmax=k; for (j=(k+1);j<n;j++)
{
Amod=fabs(A[k][j]); if (Amod>Amax)
{
Amax=Amod; kmax=j;
}
}
if (Amax<pow(10,-30)) // матрицы вырожденная
{
det=0;
return;
}
if (kmax!=k)
{
for (i=0;i<n;i++) // переставляем столбцы
{
buf=A[i][k];
A[i][k]=A[i][kmax];
A[i][kmax]=buf;
}
det=-det; L[0][m]=k; L[1][m]=kmax; m++;
}
}
95
det=det*A[k][k];
}
// расчитываем произведение А(обр)*А void MainWindow::on_pushButton_3_clicked()
{
int i,j,k;
for (i=0; i<n;i++)
{
for (j=0; j<n;j++)
{
E[i][j]=0;
for (k=0;k<n;k++)
{
E[i][j]=E[i][j]+A[i][k]*B[k][j];
}
}
}
for (i=0; i<n;i++) // Вставляем "единичную" матрицу в таблицу
{
for (j=0; j<n;j++)
{
QTableWidgetItem *item=new QTableWidgetItem; item->setText(QString("%1").arg(E[i][j])); ui->tableWidget->setItem(i,j,item);
}
}
ui->lineEdit->clear(); ui->lineEdit_2->clear();
ui->pushButton->setEnabled(false); //делаем кнопки недоступными ui->pushButton_3->setEnabled(false); ui->statusBar->showMessage(tr("!!! - ТЕСТ ВЫПОЛНЕН - !!!"),2000);
n_n=0; fl_enb=0;
}
Консольный аналог подобной программы на языке С в среде программирования CodeBlocks имеет вид:
#include <math.h> #include <time.h>
#define B(i,j) MM[i*n+j] //исходная система #define A(i,j) M[i*n+j] //приводимая система
#define E(i,j) ME[i*n+j] |
//под единичную матрицу |
#define L(i,j) LL[i*n+j] |
//массив для номеров переставленных столбцов |
float *M,*MM,*ME,*LL,det=1;
int n,m; //размерность и число перестановок int n1,n2;
void fine();
void select_Amax(int k); void test();
96
int main()
{
int i,j,c; char s[2];
SetConsoleCP(1251); //чтобы воспринимала русские буквы
SetConsoleOutputCP(1251);
printf(" *** Программа находит обратную матрицу методом Гаусса-Жордано *** "); printf("\nВведите размерность исходной матрицы: ");
scanf("%d",&n); M=malloc(n*n*sizeof(float)); //матрица - A MM=malloc(n*n*sizeof(float)); //копия A - B
ME=malloc(n*n*sizeof(float)); //для теста единичной матрицы LL=malloc(2*n*sizeof(float)); //хранит номера столбцов n1=n-1; //чтобы обращаться к компонентам матриц A, B, L
printf("Введите 0/1 - задать систему случайным образом или вручную "); scanf("%d",&c);
switch (c){ case 0:
//инициализация датчика п.с. чисел текущим временем srand(time(NULL)); for(i=0;i<n;i++)for(j=0;j<n;j++)B(i,j)=0.5-rand()/(RAND_MAX+1.0); //[-0.5;0.5] break;
default:
for (i=0;i<n;i++){ for (j=0;j<n;j++){
printf("Введите A(%d,%d): ",i,j); scanf("%f",&B(i,j));
}
}
}
printf("Введенная матрица:\n"); for (i=0;i<n;i++){
for (j=0;j<n;j++){ printf("%.5f ",B(i,j)); A(i,j)=B(i,j);
}
printf("\n");
}
//printf("A(n-1,n-1) = %.3f\n",A(n1,n1)); fine();
printf("Определитель матрицы системы = %.5f",det); if (fabs(det)<1.E-10){
printf("\nМатрица системы ВЫРОЖДЕННАЯ !");
}
else{
printf("\nОбратная матрица:\n"); for (i=0;i<n;i++){
for (j=0;j<n;j++){ printf("%.5f ",A(i,j));
}
printf("\n");
97
}
printf("\nЧисло переставленных строк - %d",m); test();
printf("\nПроизведение обратной матрицы на исходную:\n"); for (i=0;i<n;i++){
for (j=0;j<n;j++){ printf("%.5f ",E(i,j));
}
printf("\n");
}
}
printf("\nДля завершения программы введите любой символ и ENTER"); scanf("%s",&s);
return 0;
}
//вычисляет произведение обратной матрицы на исходную void test(){
int i,j,k; for(i=0;i<n;i++){
for(j=0;j<n;j++){
E(i,j)=0;
for(k=0;k<n;k++){
E(i,j)=E(i,j)+A(i,k)*B(k,j);
}
}
}
}
//процедура выбора ведущего элемента в к-ой подстроке void select_Amax(int k){
int i,kmax,j;
float Amod,Amax,buf; if(k<(n-1))
{
Amax=fabs(A(k,k)); kmax=k; for (j=(k+1);j<n;j++)
{
Amod=fabs(A(k,j)); if (Amod>Amax)
{
Amax=Amod; kmax=j;
}
}
if (Amax<1.E-10) // матрицы вырожденная
{
det=0;
return;
}
if (kmax!=k)
{
for (i=0;i<n;i++) // переставляем столбцы
{
buf=A(i,k);
98
A(i,k)=A(i,kmax);
A(i,kmax)=buf;
}
det=-det;
L(0,m)=k; //сохраняем номера переставленных столбцов
L(1,m)=kmax;
m++;
}
}
det=det*A(k,k);
}
// нахождение обратной матрицы методом Гаусса-Жордана void fine()
{
int i,j,k,m0,m1; float buf; det=1; m=0;
for (k=0;k<n;k++)
{
select_Amax(k); // выбор ведущего элемента if (det==0) return;
for (i=0;i<n;i++)
{
if (i!=k)
{
A(i,k)=-A(i,k)/A(k,k); for (j=0;j<n;j++)
{
if (j!=k)
{
A(i,j)=A(i,j)+A(i,k)*A(k,j);
}
}
}
}
for (j=0;j<n;j++)
{
if (j!=k)
{
A(k,j)=A(k,j)/A(k,k);
}
}
A(k,k)=1/A(k,k);
}
if (m>0) // переставляем строки в обратной матрице
{
for (i=(m-1);i>=0;i--)
{
m0=L(0,i);
m1=L(1,i);
for (j=0;j<n;j++)
99
{
buf=A(m0,j);
A(m0,j)=A(m1,j);
A(m1,j)=buf;
}
}
}
}
А это результаты ее работы:
Далее для сравнения приведены листинг (рис. 2.16) аналогичной консольной программы на языке Python и результаты ее работы
100
