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

Тема в разделе "Pascal and Delphi", создана пользователем Ягодка, 16 фев 2013.

  1. Ягодка

    Ягодка Member

    Регистрация:
    11 фев 2013
    Сообщения:
    6
    Симпатии:
    0
    Добрый день, уважаемые форумчане!
    В моей программе из массивов 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 - всё равно зацикливается... В архиве прилагается весь проект, текст программы приведён ниже
    Код (Delphi):
    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
     
  2. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Ого, Вы тут нам целую лекцию выдали... 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-есов и все изменения этой переменной Вы сможете отслеживать в этом окне пошагово...
    Бывает что теория (Ваше представление как должен работать написанный Вами код) отличается от практики (как оно работает на самом деле)...
    Без дебага в этом случае никак не обойтись... :)
    Пройдя по шагам Вашу процедуру Вы вскоре обнаружите место в коде, где теория расходится с практикой... ну и надеюсь поймете что нужно исправить...
    Как Вам такая лекция? :)
     
  3. Ягодка

    Ягодка Member

    Регистрация:
    11 фев 2013
    Сообщения:
    6
    Симпатии:
    0
    Замечательная лекция! А вот в универе нас такому не учат... А зря, очень полезная штука! Непременно воспользуюсь, огромное спасибо вам за отклик и неравнодушие! B)
     
  4. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Что? Правда? :)
    Ну тогда вот Вам еще пара полезных ссылок:
    Среда разработчика
    Отладка программ
     
  5. Ягодка

    Ягодка Member

    Регистрация:
    11 фев 2013
    Сообщения:
    6
    Симпатии:
    0
    Большое спасибо, очень полезные ссылки, добавила в Избранное :)
     
Загрузка...

Поделиться этой страницей