Правильно Построить Цикл Repeat-until

11.02.2013
6
0
#1
Добрый день, уважаемые форумчане!
В моей программе из массивов Kol, Gar, Rem вычитаются массивы m1 и m2, после этого действия получаются массивы Dm1 и Dm2. После того, как мы получили массивы Dm1 и Dm2, массивам In1 и In2 присваиваются нули и единицы, если выполняется условие "Dm1<Dm2". Ищется ошибка "Е1" - сумма квадратов массивов Dm1 и Dm2. Затем массивы m1 и m2 пересчитываются и снова вычитаются из массивов Kol, Gar, Rem и снова ищется ошибка "Е".
Самая первая ошибка "Е1" получается очень большой. А мне нужно, чтобы поиск новых значений массивов m1 и m2 и вычитание из массивов Kol, Gar, Rem массивов m1 и m2 продолжалось до тех пор, пока ошибка "Е" не станет меньше самой первой ошибки "Е1" в тысячу раз.
Т.е., при самом первом вычитании из массивов Kol, Gar, Rem массивов m1 и m2 мы получили ошибку "Е1"=272. Вычислили новые значения массивов m1 и m2, отняли эти значения из массивов Kol, Gar, Rem, посчитали массивы Dm1 и Dm2, присвоили массивам In1 и In2 нули и единицы, считаем ошибку "Е". Если не выполняется условие E<E1/1000, то мы снова ищем новые значения массивов m1 и m2, отнимаем, получаем массивы Dm1 и Dm2, присваиваем массивам In1 и In2 нули и единицы, считаем ошибку "Е", и так далее. Это я реализую через цикл Repeat-Until. У меня не получается правильно построить этот цикл, программа зависает (зацикливается). Я думаю, это потому что я вычитаю из массивов Kol, Gar, Rem не новые найденные значения массивов m1 и m2, а старые, полученные в самом начале программы с помощью поиска максимумов и минимумов... Пробовала в Repeat-Until переименовывать массивы m1 и m2 - всё равно зацикливается... В архиве прилагается весь проект, текст программы приведён ниже
Код:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, StdCtrls, Buttons;

type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
BitBtn1: TBitBtn;
StringGrid2: TStringGrid;
Label1: TLabel;
Label2: TLabel;
StringGrid3: TStringGrid;
Label3: TLabel;
StringGrid4: TStringGrid;
Label4: TLabel;
StringGrid5: TStringGrid;
Label5: TLabel;
StringGrid6: TStringGrid;
StringGrid7: TStringGrid;
Label6: TLabel;
Label7: TLabel;
StringGrid8: TStringGrid;
StringGrid9: TStringGrid;
Label8: TLabel;
Label9: TLabel;
StringGrid10: TStringGrid;
StringGrid11: TStringGrid;
Label10: TLabel;
Label11: TLabel;
Label12: TLabel;
Label13: TLabel;
StringGrid12: TStringGrid;
Label14: TLabel;
Label15: TLabel;
Label16: TLabel;
Label19: TLabel;
Label20: TLabel;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject); {кнопка "Кластеризация"}
var
Kol: array[1..10] of real; {Общее количество техники, которую предоставил поставщик}
Gar: array[1..10] of real; {Общая продолжительность предоставленной гарантии от поставщика в годах}
Rem: array[1..10] of real; {Общая сумма денег, потраченных на ремонт оборудования в тысячах}
m1, m2: array [1..3] of real; {центроиды}
x1,y1,z1, x2,y2,z2: real; {координаты начальных точек центроидов}
Dm1, Dm2: array[1..10] of real; {Евклидово расстояние между кластерами}
In1: array[1..10] of real; {Входит ли поставщик в кластер 1?}
In2: array[1..10] of real; {Входит ли поставщик в кластер 2?}
E1: real; {ошибка Е начальная}
E: real; {ошибка Е конечная}
ed1, ed2: integer; {количество 0 и 1 в массивах вхождения/невхождения}
sumKol1, sumGar1, sumRem1, sumKol2, sumGar2, sumRem2: real; {суммы массивов "количество", "гарантия", "ремонт"}
i: integer; {переменная для цикла}

begin
for i:=1 to 10 do begin
Kol[i]:=StrToFloat(StringGrid1.Cells[0,i-1]); {ввод элементов массива "количество"}
Gar[i]:=StrToFloat(StringGrid2.Cells[0,i-1]); {ввод элементов массива "продолжительность гарантии"}
Rem[i]:=StrToFloat(StringGrid3.Cells[0,i-1]); {ввод элементов массива "стоимость ремонта"}
end;

x1:=Kol[1]; {пусть 1ый элемент массива максимальный}
y1:=Gar[1];
z1:=Rem[1];
x2:=Kol[1]; {пусть 1ый элемент массива минимальный}
y2:=Gar[1];
z2:=Rem[1];

for i:=1 to 10 do begin {поиск максимумов и минимумов в массивах для координат начальных центроидов}
if Kol[i]>x1 then {координаты для m1-надёжный поставщик}
x1:=Kol[i];
if Gar[i]>y1 then
y1:=Gar[i];
if Rem[i]<z1 then
z1:=Rem[i];
if Kol[i]<x2 then {координаты для m2-ненадёжный поставщик}
x2:=Kol[i];
if Gar[i]<y2 then
y2:=Gar[i];
if Rem[i]>z2 then
z2:=Rem[i];
end;

m1[1]:=x1;
m1[2]:=y1;
m1[3]:=z1;
m2[1]:=x2;
m2[2]:=y2;
m2[3]:=z2;

for i:=1 to 3 do begin
StringGrid4.Cells[i-1,0]:=FloatToStr(m1[i]); {надёжный}
StringGrid5.Cells[i-1,0]:=FloatToStr(m2[i]); {ненадёжный}
end;

for i:=1 to 10 do begin
Dm1[i]:=sqrt(sqr((Kol[i]-m1[1]))+sqr((Gar[i]-m1[2]))+sqr((Rem[i]-m1[3]))); {подсчет Евклидова расстояния между кластерами}
Dm2[i]:=sqrt(sqr((Kol[i]-m2[1]))+sqr((Gar[i]-m2[2]))+sqr((Rem[i]-m2[3]))); {подсчет Евклидова расстояния между кластерами}
E1:=sqr(Dm1[i]+Dm2[i]); {ошибка Е начальная}
if Dm1[i]<Dm2[i] then {если Евклидово расстояние, найденное от первого центроида, меньше, чем Евклидово расстояние, найденное от второго центроида}
In1[i]:=1 else
In1[i]:=0;	 {элемент не входит в первый кластер, присваиваем ему 0-ложь}
if Dm1[i]<Dm2[i] then
In2[i]:=0 else
In2[i]:=1;
end;
Label13.Caption:=FloatToStrF(E1,ffFixed,5,3); {вывод ошибки Е начальной}

Repeat
ed1:=0; {обнуление количества единиц в массиве In1 - для рассчета новых координат центроида m1}
ed2:=0; {обнуление количества единиц в массиве In2 - для рассчета новых координат центроида m2}
sumKol1:=0;
sumGar1:=0;
sumRem1:=0;
sumKol2:=0;
sumGar2:=0;
sumRem2:=0;
for i:=1 to 10 do begin
Dm1[i]:=sqrt(sqr((Kol[i]-m1[1]))+sqr((Gar[i]-m1[2]))+sqr((Rem[i]-m1[3]))); {подсчет Евклидова расстояния между кластерами}
Dm2[i]:=sqrt(sqr((Kol[i]-m2[1]))+sqr((Gar[i]-m2[2]))+sqr((Rem[i]-m2[3]))); {подсчет Евклидова расстояния между кластерами}
E:=sqr(Dm1[i]+Dm2[i]); {ошибка Е конечная}
if Dm1[i]<Dm2[i] then {если Евклидово расстояние, найденное от первого центроида, меньше, чем Евклидово расстояние, найденное от второго центроида}
In1[i]:=1 else
In1[i]:=0;	 {элемент не входит в первый кластер, присваиваем ему 0-ложь}
if Dm1[i]<Dm2[i] then
In2[i]:=0 else
In2[i]:=1;
end;

for i:=1 to 10 do begin
if In1[i]=1 then begin
ed1:=ed1+1;
sumKol1:=sumKol1+Kol[i];
sumGar1:=sumGar1+Gar[i];
sumRem1:=sumRem1+Rem[i];
m1[1]:=sumKol1/ed1; {новые координаты центроида m1}
m1[2]:=sumGar1/ed1;
m1[3]:=sumRem1/ed1;
end;
if In2[i]=1 then begin
ed2:=ed2+1;
sumKol2:=sumKol2+Kol[i];
sumGar2:=sumGar2+Gar[i];
sumRem2:=sumRem2+Rem[i];
m2[1]:=sumKol2/ed2; {новые координаты центроида m1}
m2[2]:=sumGar2/ed2;
m2[3]:=sumRem2/ed2;
end;
end;
Until (E<E1/1000);

for i:=1 to 10 do begin
StringGrid12.Cells[0,i-1]:=IntToStr(i); {присвоение поставщикам свойства "надёжный" или "ненадёжный"}
if In1[i]=1 then
StringGrid12.Cells[1,i-1]:='Надёжный'
else
StringGrid12.Cells[1,i-1]:='Ненадёжный';
Label20.Caption:=FloatToStrF(E,ffFixed,5,3); {вывод результата ошибки Е конечной}
StringGrid6.Cells[0,i-1]:=FloatToStrF(Dm1[i],ffFixed,10,3); {вывод результатов Евклидова расстояния в таблицу}
StringGrid7.Cells[0,i-1]:=FloatToStrF(Dm2[i],ffFixed,10,3); {вывод результатов Евклидова расстояния в таблицу}
StringGrid8.Cells[0,i-1]:=FloatToStr(In1[i]); {вывод результатов вхождения/невхождения элементов в кластер 1}
StringGrid9.Cells[0,i-1]:=FloatToStr(In2[i]); {вывод результатов вхождения/невхождения элементов в кластер 2}
end;

for i:=1 to 3 do begin
StringGrid10.Cells[i-1,0]:=FloatToStr(m1[i]); {вывод конечных координат центроида m1}
StringGrid11.Cells[i-1,0]:=FloatToStr(m2[i]); {вывод конечных координат центроида m2}
end;
end;

end.
Посмотреть вложение k_means1.rar
 

sinkopa

Well-Known Member
17.06.2009
344
9
#2
Добрый день, уважаемые форумчане!
В моей программе из массивов Kol, Gar, Rem вычитаются массивы m1 и m2, после этого действия...
Ого, Вы тут нам целую лекцию выдали... B)
пока до конца дочитал, забыл что в начале было...
Давайте лучше я Вас научу пользоваться дебагером... :)
(1) Перейдите в редакторе в код процедуры (procedure TForm1.BitBtn1Click(Sender: TObject);)
(2) Поставьте курсор в первой исполняемой строчке кода (for i:=1 to 10 do begin)
(3) Выставьте точку останова (breakpoint): клавиша F5.
Того же эффекта можно добиться, просто кликнув в поле (левее окна редактора) напротив строки кода... :)
(4) Запустите программу в Debug-режиме. (F9 или кнопка - зеленый треугольник).
(5) Кликните в работающей программе кнопку - обработчик процедуры (BitBtn1?).
"Наткнувшись" на breakpoint, программа остановится и перед Вами откроется редактор (в месте где вы выстатили breakpoint).
Дальше, нажимая клавишу F8, Вы сможете выполнить (пройдти) процедуру по шагам.
При наведении курсора мыши на переменные в коде, в хинт окошке будут высвечиваться текущие значения этих переменных.
Если Вы выделите какую либо переменную (текст в коде) и нажмете комбинацию Ctrl+F5, переменная добавится в появившееся окошко Watch-есов и все изменения этой переменной Вы сможете отслеживать в этом окне пошагово...
Бывает что теория (Ваше представление как должен работать написанный Вами код) отличается от практики (как оно работает на самом деле)...
Без дебага в этом случае никак не обойтись... :)
Пройдя по шагам Вашу процедуру Вы вскоре обнаружите место в коде, где теория расходится с практикой... ну и надеюсь поймете что нужно исправить...
Как Вам такая лекция? :)
 
11.02.2013
6
0
#3
Замечательная лекция! А вот в универе нас такому не учат... А зря, очень полезная штука! Непременно воспользуюсь, огромное спасибо вам за отклик и неравнодушие! B)
 

sinkopa

Well-Known Member
17.06.2009
344
9
#4
Замечательная лекция! А вот в универе нас такому не учат... А зря, очень полезная штука! Непременно воспользуюсь, огромное спасибо вам за отклик и неравнодушие! B)
Что? Правда? :)
Ну тогда вот Вам еще пара полезных ссылок:
Среда разработчика
Отладка программ