011 – C++ Builder. Розробка додатку розв’язування системи лінійних алгебраїчних рівнянь методом Гауса

Розробка додатку розв’язування системи лінійних алгебраїчних рівнянь методом Гауса

Умова задачі

Задано систему лінійних алгебраїчних рівнянь:

05_01_00_011_formula01

Розробити додаток, який здійснює розв’язок системи лінійних алгебраїчних рівнянь з допомогою методу Гауса. Робота додатку повинна бути реалізована у вигляді майстра, в якому інформація для кожного наступного кроку визначається з інформації на попередньому кроку.

Виконання

1. Завантажити Borland C++ Builder.

Зберегти проект.

При збереженні проекту ім’я модуля головної форми додатку залишаємо за замовчуванням “Unit1.cpp“.

05_01_00_011_01_

Рис. 1. Форма додатку зі створеними файлами

2. Побудова головної форми додатку.

2.1. Задавання назви додатку.

Задати назву додатку. Для цього властивість Caption головної форми встановлюємо в значення “Метод Гауса“.

2.2. Встановлення властивостей форми.

Виділити форму. В Object Inspector встановити значення таких властивостей:
– властивість Border Style = bsDialog;
– властивість Position = poScreenCenter;
– у властивості Font вибрати параметри шрифту: шрифт Tahoma, розмір шрифту 12 (рис. 2).

05_01_00_011_02_

Рис. 2. Встановлення параметрів шрифту головної форми додатку

У результаті, форма додатку прийме вигляд як показано на рис. 3.

05_01_00_011_03u

Рис. 3. Головна форма додатку

 

2.3. Компонент типу TGroupBox.

Розміщуємо на формі компонент (елемент управління) типу TGroupBox з палітри компонент “Tool Palette“.

05_01_00_011_04u

Рис. 4. Компонент типу TGroupBox

У результаті, система створить об’єкт-змінну з іменем GroupBox1.

Змінюємо розміри компонента GroupBox1 на всю ширину вікна головної форми.

Властивість Caption компонента GroupBox1 встановлюємо в значення ” Умова задачі “. Форма додатку матиме вигляд, як показано на рисунку 5.

05_01_00_011_05u

Рис. 5. Форма додатку після розміщення компоненту TGroupBox

 

2.4. Компонент типу TLabel.

Розміщуємо компонент типу TLabel в області компонента TGroupBox. Автоматично створюється об’єкт-змінна з іменем Label1 (рис. 6).

Встановлюємо властивість WordWrap компонента Label1 в значення “true” (рис. 6).

З допомогою мишки змінюємо ширину виведення тексту компонента Label1 (рис. 6).

05_01_00_011_06u

Рис. 6. Компонент Label1, властивість WordWrap

Властивість Caption компонента Label1 встановлюємо в значення:

Розв’язати систему лінійних алгебраїчних рівнянь методом Гауса

У результаті, форма додатку прийме вигляд, як показано на рисунку 7.

05_01_00_011_07u

Рис. 7. Форма додатку після розміщення компонента Label1

 

2.5. Компоненти типу TButton.

Розміщуємо на формі компоненти типу TButton. У результаті утвориться два об’єкти-змінні з іменами Button1 і Button2.

Для кращої наочності змінюємо розміри компонент так як показано на рисунку 8.

05_01_00_011_08u

Рис. 8. Форма додатку з розміщеними компонентами Button1 і Button2

Встановлюємо такі властивості компонент Button1 і Button2:
– у компоненті Button1 властивість Caption = “Вихід”;
– у компоненті Button2 властивість Caption = “Розрахунок >>”.

У результаті форма додатку прийме вигляд, як показано на рисунку 9.

05_01_00_011_09u

Рис. 9. Головна форма додатку після розміщення усіх компонент

 

3. Програмування події кліку на кнопці “Вихід”.

Викликаємо подію OnClick компонента Button1, що відповідає кнопці “Вихід” (рис. 10). Подія розміщується на вкладці Events в Object Inspector.

Процес програмування події OnClick детально описаний тут.

05_01_00_011_10u

Рис. 10. Виклик події OnClick компонента Button1

У результаті, відкриється вікно з програмним кодом методу обробки події. Між дужками { } вводимо виклик методу Close().

Метод Close() закриває вікно головної форми додатку і здійснює усі необхідні операції зі звільнення пам’яті, ресурсів тощо.

Весь текст методу обробки події має вигляд:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Close(); 
}

Тепер можна запустити проект на виконання (клавіша F9) і протестувати його роботу.

 

4. Побудова форми введення кількості рівнянь n.

4.1. Розміщення компонент на формі та їх налаштування.

Процес створення нової форми детально описаний тут.

Для створення нової форми викликаємо команду

File -> New -> Form C++ Builder

У результаті, створиться нова форма, як показано на рисунку 11.

Зберігаємо форму під іменем “Unit2.cpp“. Створюються файли, що відповідають формі:
– файл “Unit2.h“, що містить описи глобальних змінних та підключення інших модулів;
– файл “Unit2.cpp“, що містить реалізацію методів форми;
– файл “Unit2.dfm“, що містить опис зображення форми на екрані (розміри вікна, координати форми відносно вікна екрану, значення кольорів та інше).

Новоствореній формі відповідає об’єкт з іменем Form2. З допомогою цього імені можна доступатись до властивостей та методів форми Form2.

05_01_00_011_11_

Рис. 11. Новостворена форма Form2

Здійснимо налаштування форми Form2.

Спочатку налаштовуємо властивості форми:
– властивість Caption = “Задайте кількість рівнянь”;
– властивість BorderStyle = bsDialog;
– властивість Position = poScreenCenter;
– у властивості Font вибрати параметри шрифту: шрифт Tahoma, розмір шрифту 12.

Розміщуємо на формі такі компоненти:
– компонент типу TGroupBox якому відповідатиме об’єкт GroupBox1;
– компонент типу TLabel, розміщується всередині області компонента GroupBox1. Компоненту типу TLabel відповідає змінна Label1;
– компонент типу TEdit, розміщується всередині області компонента GroupBox1. Цьому компоненту відповідає об’єкт (змінна) Edit1;
– два компонент типу TButton, якому відповідають об’єкти з іменами Button1 і Button2.



Здійснимо налаштування властивостей компонент:
– у компоненті GroupBox1 значення властивості Caption = “” (пустий рядок);
– у компоненті Label1 значення властивості Caption = “n = “;
– у компоненті Edit1 значення властивості Text = “”;
– у компоненті Button1 значення властивості Caption = “<< Назад”;
– у компоненті Button2 значення властивості Caption = “Продовжити >>“.

Після розміщення компонент та корегування розмірів форми, форма Form2 має вигляд як показано на рисунку 12.

05_01_00_011_12u

Рис. 12. Форма Form2 після розміщення та налаштування усіх компонент

 

4.2. Програмування обробників подій форми Form2.

У формі Form2 програмуємо два обробники подій:
– обробник події OnClick кліку на кнопці “<< Назад“;
– обробник події OnClick кліку на кнопці “Продовжити >>“.

Лістинг обробника події кліку на кнопці Button1 (“<< Назад“):

void __fastcall TForm2::Button1Click(TObject *Sender)
{
  ModalResult = mrNo; 
}

Лістинг обробника події кліку на кнопці Button2 (“Продовжити >>“):

void __fastcall TForm2::Button2Click(TObject *Sender)
{
  ModalResult = mrOk; 
}

Глобальна змінна ModalResult відповідає за стан форми. Якщо глобальна змінна ModalResult=0, то це означає що форма відкрита як модальне вікно. Як тільки значення ModalResult стане ненульовим, то форма Form2 закриється з кодом повернення, що міститься у ModalResult.

Таким чином, якщо користувач зробить клік на кнопці Button1, то форма Form2 закриється з кодом повернення mrNo. Якщо користувач зробить клік на кнопці Button2, то форма Form2 закриється з кодом повернення mrOk.

 

5. Побудова форми введення коефіцієнтів у рівняннях.

5.1. Розміщення компонент на формі та їх налаштування.

Створення форми відбувається стандартним шляхом так само як описано в п. 4.

Зберігаємо форму під іменем за замовчуванням “Unit3.cpp“.

Після створення форми отримаємо об’єкт з іменем Form3. З допомогою цього об’єкту можна буде використовувати методи та властивості форми Form3.

Даній формі відповідають файли з іменами “Unit3.h“, “Unit3.cpp” та “Unit3.dfm“.

Спочатку здійснимо налаштування властивостей форми Form3 так як описано в п. 4:
– властивість Caption = “Ввід коефіцієнтів рівнянь”;
– властивість BorderStyle = bsDialog;
– властивість Position = poScreenCenter;
– у властивості Font вибрати параметри шрифту: шрифт Tahoma, розмір шрифту 12.

Для побудови форми введення коефіцієнтів рівнянь використаємо такі компоненти:
– два компоненти типу TLabel. Автоматично будуть створені об’єкти з такими іменами: label1 та label2;
– компонент типу TStringGrid (рис. 13) для введення коефіцієнтів, що розміщуються у лівій частині системи рівнянь. Компонент TStringGrid розміщується у вкладці Additional панелі інструментів “Tool Palette“. Створюється об’єкт з іменем StringGrid1;
– компонент типу TStringGrid (рис. 13) для введення коефіцієнтів, що розміщуються у правій частині системи рівнянь. Створюється об’єкт з іменем StringGrid2;
– два компоненти типу TButton (кнопки “<< Назад” і “Продовжити >>“). Створюються два об’єкти з іменами Button1 і Button2.

05_01_00_011_13u

Рис. 13. Компонент TStringGrid на палітрі компонент

Після розміщення компонент та корегування їх розмірів форма Form3 матиме приблизно такий вигляд як показано на рисунку 14.

05_01_00_011_14u

Рис. 14. Форма Form3

Формуємо властивості компонент форми Form3:
– у компоненті Label1 властивість Caption = “Коефіцієнти у лівій частині рівняння”;
– у компоненті Label2 властивість Caption = “Права частина”;
– у компоненті Button1 властивість Caption = “<< Назад”;
– у компоненті Button2 властивість Caption = “Продовжити >>”.

Формуємо властивості компонентів типу TStringGrid:
– у компоненті StringGrid1 властивість FixedCols = 0 (кількість фіксованих колонок);
– у компоненті StringGrid1 властивість FixedRows = 0 (кількість фіксованих рядків);
– у компоненті StringGrid2 властивість FixedCols = 0;
– у компоненті StringGrid2 властивість FixedRows = 0;
– у компоненті StringGrid1 вибираємо вкладку Options і встановлюємо опцію goEditing у значення “true“;
– у компоненті StringGrid2 у вкладці Options опція goEditing = “true”.

05_01_00_011_15u

Рис. 15. Встановлення опції goEditing у вкладці Options компонента StringGrid1

Після виконаних дій, форма Form3 матиме вигляд як показано на рисунку 16.

05_01_00_011_16u

Рис. 16. Форма Form3 після остаточного формування

 

5.2. Програмування обробників подій форми Form3.

Програмуємо обробники подій OnClick кліку на кнопках Button1 і Button2 форми Form3.

Лістинг обробників подій наведено нижче.

// кнопка "<< Назад"
void __fastcall TForm3::Button1Click(TObject *Sender)
{
  ModalResult = mrNo;
}

// кнопка "Продовжити >>"
void __fastcall TForm3::Button2Click(TObject *Sender)
{
  ModalResult = mrOk;
}

6. Створення форми виведення результату.

Останньою в додатку створюється форма, яка буде виводити результат обчислень. Процес створення та збереження форми детально описано тут. При збереженні форми залишаємо ім’я за замовчуванням “Unit4.cpp“.

У результаті отримуємо об’єкт з іменем Form4.
Новостворена форма Form4 описується у файлі “Unit4.dfm“. Також формі відповідають файли “Unit4.h” та “Unit4.cpp“.

 

6.1. Побудова форми Form4.

Спершу налаштовуємо властивості форми Form4:
– властивість Caption = “Результат”;
– властивість BorderStyle = bsDialog;
– властивість Position = poScreenCenter;
– у властивості Font вибрати параметри шрифту: шрифт Tahoma, розмір шрифту 12.

Також корегуємо розміри форми.

Наступним кроком йде розміщення на формі компонент.

Розміщуємо на формі наступні компоненти (рис. 17):
– один компонент типу TLabel;
– два компоненти типу TStringGrid;
– один компонент типу TButton.

Корегуємо розміри та позиції компонент для зручного відображення.

Після розміщення компонент буде створено об’єкти з такими іменами: Label1, StringGrid1, StringGrid2, Button1. У компоненті StringGrid1 виводяться номери змінних величин x у рівнянні. У компоненті StringGrid2 виводяться значення розв’язки системи рівнянь.

Налаштовуємо компоненти форми наступним чином:
– у компоненті Label1 властивість Caption = “Рішення системи”;
– у компоненті Button1 властивість Caption = “OK”;
– у компоненті StringGrid1 властивості FixedCols = 0 та FixedRows = 0;
– у компоненті StringGrid2 властивості FixedCols = 0 та FixedRows = 0.

Після розміщення та налаштування компонент, форма Form4 матиме вигляд як показано на рисунку 17.

05_01_00_011_17u

Рис. 17. Форма Form4 після остаточного формування

 

6.2. Програмування події кліку на кнопці “ОК” форми Form4.

Лістинг обробника події кліку на кнопці “ОК” наступний:

void __fastcall TForm4::Button1Click(TObject *Sender)
{
  ModalResult = mrOk; 
}

 

7. Написання програмного коду розрахунку.

7.1. Підключення модулів “Unit2.h“, “Unit3.h“, “Unit4.h” до модуля “Unit1.h“.

Для того, щоб з головної форми додатку Form1 викликати другорядні форми, потрібно здійснити їх підключення у модулі “Unit1.h“.

Підключення модулів форм Form2, Form3, Form4 до форми Form1 здійснюється стандартним для мови C/C++ способом.
Спочатку потрібно перейти у модуль “Unit1.h“.

Потім після рядків

#ifndef Unit1H
#define Unit1H
//-------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>

потрібно ввести такий текст:

#include "Unit2.h"
#include "Unit3.h"
#include "Unit4.h"

 

7.2. Введення змінних та констант в модуль “Unit1.h

З допомогою Project Manager переходимо у модуль “Unit.h“.

Спочатку вводимо константу MaxN, яка позначає максимально допустиму кількість рівнянь. Для цього, після рядків

...
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "Unit2.h"
#include "Unit3.h"
#include "Unit4.h"

вводимо текст

#define MaxN 20

У розділ private класу TForm1 форми вводимо внутрішні змінні:
n – кількість рівнянь;
A – двовимірний масив розміром nґ(n+1) коефіцієнтів при змінних у рівняннях;
X – одновимірний масив розв’язків рівнянь;
– змінна цілого типу f_not, яка позначає наявність або відсутність рішення в системі рівнянь.

Також у розділ public вводимо функцію Calc(), яка безпосередньо буде здійснювати розрахунок за методом Гауса.

У загальному, опис класу в модулі Unit1.h виглядає наступним чином:

...
class TForm1 : public TForm
{
__published: // IDE-managed Components
 TGroupBox *GroupBox1;
 TLabel *Label1;
 TButton *Button1;
 TButton *Button2;
 void __fastcall Button1Click(TObject *Sender);
private: // User declarations
 int n; // кількість рівнянь
 float A[MaxN][MaxN+1]; // матриця коефіцієнтів
 float X[MaxN]; // масив 
 bool f_not;

public: // User declarations
 __fastcall TForm1(TComponent* Owner);
 int Calc(void);
};
...

7.3. Написання функції Calc() розв’язку системи рівнянь методом Гауса.

З допомогою Project Manager переходимо у файл “Unit1.cpp“.

У файлі “Unit1.cpp” вводимо текст реалізації функції Calc(), оголошеного в модулі “Unit1.h“.

Функція Calc() повертає 0, якщо система рівнянь не визначена. В іншому випадку повертається значення 1.

Лістинг методу Calc() без пояснень деталей алгоримту наступний:

int TForm1::Calc(void)
{
 int u,k,m,i,j;
 int f_exit;
 float t;
 u = 0;
 f_not = false;
 while (u!=n)
 {
   u++;
   k=u;
   while (A[k][u]==0)
   {
     k++;
     if (k>n)
     {
       f_not = true; // система не визначена
       return 0;
     }
   }
 
   if (k!=u)
   {
     for (m = u; m<=n+1; m++)
     {
       t = A[u][m];
       A[u][m] = A[k][m];
       A[k][m] = t; 
     }
   }

   for (j = n+1; j >= u; j--)
     A[u][j] = A[u][j]/A[u][u];

    m = n + 1;
    if ((k+1)<=n)
      for (i = k+1; i <= n; i++)
        for (j = u+1; j <= m; j++)
          A[i][j] = A[i][j]-A[i][u] * A[u][j];
 }

 // Побудова масиву результатів
 for (i = n; i >= 1; i--)
 {
   X[i] = A[i][m];
   if (i!=1)
     for (k = i-1; k>=1; k--)
       A[k][m] = A[k][m] - A[k][i] * X[i];
 }
 return 1; // є рішення
}

 

7.4. Програмування події кліку на кнопці “Розрахунок“.

Лістинг обробника події кліку на кнопці “Розрахунок” (Button2) наступний:

void __fastcall TForm1::Button2Click(TObject *Sender)
{
 int i, j, res;
 Form1->Visible = false; // ховаємо форму
 if (Form2->ShowModal()==mrOk) // вивід форми введення числа рівнянь n
 {
   n = StrToInt(Form2->Edit1->Text); // взяли число рівнянь
   Form3->StringGrid1->ColCount = n; // побудова матриці - к-сть колонок
   Form3->StringGrid1->RowCount = n; // кількість рядків матриці
   Form3->StringGrid2->RowCount = n; // права частина
   Form3->StringGrid2->ColCount = 1;
   // побудова форми виведення результату
   Form4->StringGrid1->RowCount = n;
   Form4->StringGrid1->ColCount = 1;
   Form4->StringGrid2->RowCount = n;
   Form4->StringGrid2->ColCount = 1;
   for (i = 1; i <= n; i++)
     Form4->StringGrid1->Cells[0][i-1] = "X[" + IntToStr(i) + "]=";

   if (Form3->ShowModal()==mrOk) // вивід форми введення даних
   {
     // Побудова матриці A
     for (i = 1; i <= n; i++)
       for (j = 1; j <= n; j++)
         A[i][j] = StrToFloat(Form3->StringGrid1->Cells[j-1][i-1]);
     
     // стовпчик B
     for (i = 1; i <= n; i++)
       A[i][n+1] = StrToFloat(Form3->StringGrid2->Cells[0][i-1]);
     Calc();

     if (!f_not)
     {
       // Формування масиву X - результатів
       // занесення результату у форму Form4
       for (i=1; i<=n; i++)
         Form4->StringGrid2->Cells[0][i-1] =  FloatToStrF(X[i],ffFixed,8,2);
         Form4->ShowModal(); // виведення форми результату
     }
     else
       MessageDlg("Система не визначена!", mtConfirmation, TMsgDlgButtons() << mbOK, 0);
   }
 }
 Form1->Visible = true;
}

Пояснимо деяку фрагменти коду. Виведення форми відбувається функцією ShowModal(). Перетворення цілого типу в рядок відбувається функцією IntToStr().

Перетворення з рядка в дійсний тип реалізовано функцією StrToFloat().

Перетворення з дійсного типу в рядок відбувається з допомогою функції FloatToStrF().

Для виведення повідомлення про невизначеність системи рівнянь використовується функція MessageDlg().