Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
|
A1:= b[1]*(a[2,2]*a[3,3]-a[2,3]*a[3,2])-b[2]*(a[1,2]*a[3,3]-a[1,3]*a[3,2])+b[3]*(a[1,2]*a[2,3]-a[2,2]*a[1,3]); //вычисляем алг. дополнение А1
A2:=a[1,1]*(b[2]*a[3,3]-b[3]*a[3,2])-a[2,1]*(b[1]*a[3,3]-a[1,3]*b[3])+a[3,1]*(b[1]*a[2,3]-b[2]*a[1,3]); //вычисляем алг. дополнение А2
A3:= a[1,1]*(a[2,2]*b[3]-b[2]*a[3,2])-a[2,1]*(a[1,2]*b[3]-b[1]*a[3,2])+a[3,1]*(a[1,2]*b[2]-a[2,2]*b[1]); //вычисляем алг. дополнение А3
по факту главная часть завершена.
Если не брать во внимание, что вычисление обратной матрицы весьма трудоёмко, можно уже в таком виде выводить на печать. Но рано!
Итого на этом этапе дополняем кодом чуть ниже вывода А1,А2,А3.
Memo1.Lines.Add('A1='+inttostr(A1)+' A2='+inttostr(A2)+' A3='+inttostr(A3)); //выводим А1,А2,А3
Memo1.Lines.Add('решение системы уравнений X='+inttostr(A1)+'/'+inttostr(A0)+ ' Y='+inttostr(A2)+'/'+inttostr(A0)+' Z='+inttostr(A3)+'/'+inttostr(A0)); //выводим решение системы уравнений
По сути, "Метод Крамера" сделан. Годится для вывода ответов для преподавателя в его "шпаргалку" для проверки решений студентов.
Далее уже идут сначала "косметические" дополнения, а после конкретно самое тяжёлое — вычисление и вывод обратной матрицы. Она только на бумаге вручную легко считается. Закодировать формулу весьма тяжкая задача.
— Четвёртый этап: вывод нормального вида системы уравнений
Собственно это составить не представляется особого труда, но есть одна тонкость.
Состоит в том, что если просто ставить коэффициенты в строку вывода, то будут встречаться несуразности вида -2x+-5y+-3z=-2
Вот это самое чередование плюс-минус весьма не эстетично.
Для исправления этой неприятности на выводе в строку применю самый элементарный приём. Но для этого придётся ввести шесть строковых величин s[i,j].
Так как отдельный вывод b1,b2,b3 не нужен, ставим на строке "заглушку" в виде //(комментарий). Ведь по сути этот вывод был "строительными лесами" и служил лишь для проверки, что всё нормально считается. Теперь же они и так будет в строке системы уравнений.
Итого вывод на печать
//цикл для определения содержания строковой s для заполнения системы уравнений
for k:=1 to 3 do
for m:=1 to 3 do
begin
if a[k,m]>=0 then s[k,m]:='+'
else if a[k,m]<0 then s[k,m]:=''; // если коэффициент отрицательный, то выводиться должен чисто коэффициент со своим знаком и только
end;
// выводим систему уравнений
Memo1.Lines.Add( IntToStr(a[1,1])+'x '+s[1,2]+IntToStr(a[1,2])+'y '+s[1,3]+IntToStr(a[1,3])+'z = '+ IntToStr(b[1]));
Memo1.Lines.Add( IntToStr(a[2,1])+'x '+s[2,2]+IntToStr(a[2,2])+'y '+s[2,3]+IntToStr(a[2,3])+'z = '+ IntToStr(b[2]));
Memo1.Lines.Add( IntToStr(a[3,1])+'x '+s[3,2]+IntToStr(a[3,2])+'y '+s[3,3]+IntToStr(a[3,3])+'z = '+ IntToStr(b[3]));
A1:= b[1]*(a[2,2]*a[3,3]-a[2,3]*a[3,2])-b[2]*(a[1,2]*a[3,3]-a[1,3]*a[3,2])+b[3]*(a[1,2]*a[2,3]-a[2,2]*a[1,3]); //вычисляем алг. дополнение А1
A2:=a[1,1]*(b[2]*a[3,3]-b[3]*a[3,2])-a[2,1]*(b[1]*a[3,3]-a[1,3]*b[3])+a[3,1]*(b[1]*a[2,3]-b[2]*a[1,3]); //вычисляем алг. дополнение А2
A3:= a[1,1]*(a[2,2]*b[3]-b[2]*a[3,2])-a[2,1]*(a[1,2]*b[3]-b[1]*a[3,2])+a[3,1]*(a[1,2]*b[2]-a[2,2]*b[1]); //вычисляем алг. дополнение А3
//вывод вычисленных значений А,А1,А2, А3 и решений системы уравнений
Memo1.Lines.Add('A='+inttostr(A0)); //выводим значение определителя А;
Memo1.Lines.Add('A1='+inttostr(A1)+' A2='+inttostr(A2)+' A3='+inttostr(A3)); //выводим А1,А2,А3
Memo1.Lines.Add('решение системы уравнений X='+inttostr(A1)+'/'+inttostr(A0)+ ' Y='+inttostr(A2)+'/'+inttostr(A0)+' Z='+inttostr(A3)+'/'+inttostr(A0)); //выводим решение системы уравнений
— Шаг третий — вывод ТРЁХ заданий на вариант
Если внутри вариантов будет три задания, причём разные то, естественно понадобится повторное вычисление систем уравнений и их решений. Однако, как указывалось ранее, особо злючий момент — вычисление обратной матрицы". А это третье задание.
Отсюда и алгоритм:
внутри цикла, что охватывает генерацию "Вариант N", вводится ещё один цикл, который отвечает за номера заданий. Пусть эти номера у нас будут обозначаться переменной с именем NN. Таким образом мы можем вставить отдельно блок решения и вывода на Мемо обратной матрицы в третьем задании.
Поэтому:
— Первый этап: разделение вариантов на три задания
Выглядеть это будет так:
for N:=1 to SpinEdit1.Value do
begin
Memo1.Lines.Add('Вариант '+inttostr(N)); //выводит "вариант N"
for NN:=1 to 3 do
begin
Memo1.Lines.Add('Задание '+inttostr(NN));
if NN=1 then Memo1.Lines.Add('Решите систему уравнений методом Гаусса')
else if NN=2 then Memo1.Lines.Add('Решите систему уравнений методом Крамера')
else Memo1.Lines.Add('Решите систему уравнений методом обратной матрицы');
Далее, то что уже написанный код, но в хвосте решений следующий блок:
if NN=3 then
begin
Memo1.Lines.Add('Обратная матрица третьего задания');
//(далее формула вычисления и выведение обратной матрицы в Мемо)
end; // закрыт if с обратной матрицей
end; // закрыт цикл NN
end; //закрыт цикл для N
Последние приписки для end; это для описания. В Дельфи связки begin-end подсвечиваются программно и видно что где открывается-закрывается. Однако вот такая форма для разработки блоков удобна: где-то накатал с "комментами", а после вставил в Дельфи. Позатирать лишние строки комментов — пара секунд.
— Второй этап: разработка кода на вычисление и вывод обратной матрицы
Здесь предоставляю читателям самим вывести формулу обратной матрицы (для тренировки) по алгоритмам и формулам, приведённым здесь: https://ru.wikipedia.org/wiki/Обратная_матрица
см. параграф "С помощью матрицы алгебраических дополнений".
Вставка блока будет делаться так:
if NN=3 then
begin
Memo1.Lines.Add('Обратная матрица третьего задания');
//(далее формула вычисления элементов обратной матрицы)
c[1,1]:=
..........
c[3,3]:=
Memo1.Lines.Add(inttostr(c[1,1])+'/'+inttostr(A0)+' '+inttostr(c[1,2])+'/'+inttostr(A0)+' '+inttostr(c[1,3])+'/'+inttostr(A0));
Memo1.Lines.Add(inttostr(c[2,1])+'/'+inttostr(A0)+' '+inttostr(c[2,2])+'/'+inttostr(A0)+' '+inttostr(c[2,3])+'/'+inttostr(A0));
Memo1.Lines.Add(inttostr(c[3,1])+'/'+inttostr(A0)+' '+inttostr(c[3,2])+'/'+inttostr(A0)+' '+inttostr(c[3,3])+'/'+inttostr(A0));
end; // закрыт if с обратной матрицей
end; // закрыт цикл NN
— — —
После этого вставляем пару строк для того, чтобы отделить очередной вариант от следующих.
Memo1.Lines.Add(' ');
Memo1.Lines.Add(' ');
//Дальше я вставил блок страховки от ошибок. Просто обнуляются переменные перед их повторным использованием
for k:=1 to 3 do
begin
for m:=1 to 3 do
begin
a[k,m]:=0;
A0:=0;
c[k,m]:=0;
end;
end; // закрыт блок N
end; // конец процедуры обработки нажатия клавиши "Вычислить"
Дело в том, что иногда "на ровном месте" уже полученный исполняемый файл выдаёт сообщение об ошибке и виснет, несмотря на ранее устойчивую и правильную работу. Принудительное обнуление как раз и позволяет программе нормально работать без сбоев. Не знаю как у вас, но у меня вышло так.
— Шаг третий: контроль работы и отсечение несуразностей
Просто так код может и работает. Компилятор слопает всё, что не противоречит правилам его работы и выдаст вам исполняемый файл.
Но вот правильно ли всё в формулах написано, надо проверять.
При запуске программы берём любой вариант и выборочно пересчитываем вручную то, что надо вычислять. А именно: А0, А1,А2,А3.
При тестовом прогоне и пересчёте варианта вылезло то, что в формуле вычисления А2 была допущена мелкая ошибка в индексах. Исправлено.
При следующем прогоне уже всё считалось правильно.
Ещё одна несуразность — возможность выставления в индексы для x,y,z нулей. Если их на систему уравнений один-два, это ещё терпимо. Но есть ненулевая вероятность появления нулей у половины и более индексов при НЕНУЛЕВОМ значении определителя. Что весьма нехорошо с т.з. проверки умений учащихся. Т.к. натуральная холява.
Последнее "лечится" легко.
Просто вокруг блока, где назначаются значения конкретным индексам ставим цикл с постусловием что число не должно быть равно нулю.
Вот так:
repeat
l:=Random(2);
if l>0 then
a[k,m]:=Random(4) // присваиваем положительные случайные целые числа от 0 до 9 элементам массива если l>0
else a[k,m]:=(-1)*Random(4); // присваиваем отрицательные случайные целые числа от 0 до 9 элементам массива если l=0
until(a[k,m]<>0);
_________________________
Можно и ещё "блох" поотлавливать. Но и этого уже достаточно.
Post Scriptum:
Кстати для студентов!
Скопипастить код с решениями системы методом Крамера, с вычислением обратной матрицы(если вы его таки сделали ;-) ), а после переделать полученный код под решение КОНКРЕТНЫХ систем с КОНКРЕТНЫМИ коэффициентами — элементарно!
Delphi вам в лапы и ветер в спину! :-))
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
|