Помощь - Поиск - Пользователи - Календарь
Полная версия: СМО с ожиданием
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Jill
Не посылайте в FAQ, плз. Я там была. Конкретно по этой теме там пару слов wink.gif

Только начала разбираться, и уже появилось несколько камней преткновения.

Условие. Необходимо создать СМО с ожиданием из 10 элементов, где:
- время прибытия и время обслуживания - случайные числа с нормальным распределением (просто random не подходит)
- остальные компоненты просчитываются, но об этом позже
- соблюдается принцип очереди FIFO в динамике

Код (это не все, только то, что вызывает вопросы):
type
TPClient=^TClient; {описание элементов очереди}
TClient=record
t1:real; {время прибытия}
t2:real; {время ожидания}
next:TPClient;
end;
var
head,node:TPClient;
naf: boolean;
nay: real;
{процедура вывода на экран}
procedure Print1;
var
curr:TPClient;
n:integer;
begin
curr:=head;
while (curr<>NIL)do
begin
writeln(curr^.t1,' ',curr^.t2);
curr:=curr^.next;
end;
end;
{функция генерирования случайных чисел по закону норм.распределения}
function nrandom:real; {вопрос 1}
var u1,u2:real;
begin
naf:=not naf; if naf then nrandom:=nay
else begin
repeat
u1:=random;
until u1>0;
u1:=sqrt(-2*ln(u1));
u2:=random*pi*2;
nay:=u1*cos(u2);
nrandom:=u1*sin(u2);
end;
end;
{создание очереди}
procedure Queure;
var
node:TPClient;
curr:TPClient;
pred:TPClient;
n:integer;
begin
n:=0;
naf:=true;
while n<10 do begin
new(node);
node^.t1:=nrandom;
node^.t2:=nrandom; {вопрос 3}
curr:=head;
pred:=NIL;
while (curr<>NIL) and (node^.t1>curr^.t1) do {вопрос 2}
begin
pred:=curr;
curr:=curr^.next;
end;
if pred=NIL
then
begin
node^.next:=head;
head:=node;
end
else
begin
node^.next:=pred^.next;
pred^.next:=node;
end;
n:=n+1; end;
end;

begin
Queure;
Print1;
readln;
end.

Вопросы:
1. Во всех алгоритмах норм.распределения генерируемые числа - вещественные, а мне необходимы целые. Плюс - числа должны быть >=0. Как грамотно их преобразовать?
2. В первой колонке сформированых чисел, по-моему, должен быть порядок - этот пришел в 0-ой момент времени, этот в 1-ый и т.д. Во второй - упорядочивание не должно проводиться. Как разобраться с этим?
3. Во второй колонке не должен попадаться 0 (время обслуживания не может быть таковым). Достаточно ли просто прибавить 1?
И самый главный вопрос. После прогона получаются ОДИНАКОВЫЕ наборы чисел! Мне необходимо отразить результаты нескольких прогонов, а какой с них толк, если они одинаковые!

Помогите разобраться unsure.gif
Бродяжник
Если идет речь о нормально распределенных случайных числах, то они ведь распределены на каком-то интервале, верно?
Итак, имеем
Fi - очередное сгенерированное Вашей функцией вещественное случайное число. Видимо, оно будет в интервале от 0 до 1? Или, в общем случае, от F1 до F2.
TPi - очередное время прибытия. Тоже, надо полагать в некотором интервале - от TP1 до ТP2.
TOi - очередное время обслуживания. В некотором интервале - от TО1 до ТО2.
Тогда
Код
TPi := TP1 + (TP2-TP1)*(Fi-F1)/(F2-F1);
TOi := TO1 + (TO2-TO1)*(Fi-F1)/(F2-F1);

Если Fi лежит в интервале от 0 до 1, тогда формулы упрощаются.
Код
TPi := TP1 + (TP2-TP1)*Fi;
TOi := TO1 + (TO2-TO1)*Fi;

Если нужны именно целые числа (integer), то результат вычислений округляем (TPi := round(...)).
По поводу наборов чисел. Поскольку Ваша функция случайных чисел использует стандартный random, то перед каждым прогоном один раз вызываем процедуру randomize - и будет счастье.
Jill
Так, с этим разобралась smile.gif Спасибо smile.gif
Кст, отдельное спасибо за randomize - вылетело из головы smile.gif

Тут другой вопрос возник. Динамика. Что-то я с ней никак подружиться не могу unsure.gif

Как грамотно при закрытии проги уничтожать очередь, чтоб мусора не оставалось?
volvo
Цитата(Jill @ 26.07.2006 15:23)
Как грамотно при закрытии проги уничтожать очередь, чтоб мусора не оставалось?
Наверное, так:

procedure Clear;
var curr, deleting: TPClient;
begin
curr := head;
while curr <> nil do begin
deleting := curr;
dispose(deleting);
curr := curr^.next;
end;
head := nil;
end;

begin
writeln('before: ', memavail); { Проверяем: доступная память в начале работы }

Queure;
Print1;
Clear; { <--- Очищаем очередь }

writeln('after: ', memavail); { Доступная память после удаления очереди }
readln;
end.
Jill
Ок, с мусором разобрались. Спасибо smile.gif

Тут еще вопрос возник. Переписала процедуру построения очереди - мне кажется, предыдущая версия (вставка элементов в упорядоченный список) была мухляжом wink.gif

Так честнее:
procedure Queure;
var
node:TPClient;
n:integer;
F1,F2:real;
begin
n:=0;
naf:=true;
while (n<10) do begin {вроде, можно тут поменять, но ведь node еще не создан...}
new(node);
F1:=nrandom;
F2:=nrandom;
curr:=head;
pred:=NIL;
while (curr<>NIL) do
begin
pred:=curr;
curr:=curr^.next;
end;
if pred=NIL
then
begin
node^.next:=head;
head:=node;
node^.t1:=Abs(round(F1));
end
else
begin
node^.next:=pred^.next;
pred^.next:=node;
node^.t1:=Abs(round(F1))+pred^.t1;
end;
n:=n+1;
node^.t2:=Abs(round(1+(10-1)*(F2-1)/(10-1)))+1;
end;
end;


Суть вопроса. По-моему, я ошиблась в условии - работа системы ограничена во времени, а не по количеству требований. Получается, система должна работать 10 единиц времени (без учета задержки из-за последнего требования). То бишь, до момента, когда node^.t1=10. Как организовать этот цикл? По-моему, repeat в динамике нельзя использовать...? unsure.gif

И еще один глупый вопрос (не ругайте, мне и так стыдно unsure.gif ). Как прервать работу программы при зацикливании?
volvo
Цитата(Jill @ 28.07.2006 13:13)
По-моему, repeat в динамике нельзя использовать...? unsure.gif

blink.gif Это почему? В смысле, почему ты думаешь, что Repeat нельзя, а While - можно? Кстати, даже если ты не хочешь переделывать цикл на Repeat, то всегда можно сделать так:

while naf do begin
...
naf := (node^.t1 < 10)
{ Как только node^.t1 станет = или больше 10, цикл прервется на следующей итерации }
end;


Цитата(Jill @ 28.07.2006 13:13)
Как прервать работу программы при зацикливании?
В смысле, как программно определить зацикливание и выйти из цикла, или у тебя запущенная программа зациклилась, и ты хочешь прервать ее работу?

P.S.
Цитата(Jill @ 28.07.2006 13:13)
Так честнее:
Еще честнее было бы не бегать все время по очереди, а сделать в TClient ссылку не только на Next, но и на Prev... rolleyes.gif
Jill
Цитата
Это почему? В смысле, почему ты думаешь, что Repeat нельзя, а While - можно?

Понятия не имею... Один препод (не по этому предмету...фух wink.gif ) почему-то жутко ругается на repeat в динамике. Это не так, да?

Цитата
В смысле, как программно определить зацикливание и выйти из цикла, или у тебя запущенная программа зациклилась, и ты хочешь прервать ее работу?

Второе - какими кнопками прервать wink.gif

Цитата
Еще честнее было бы не бегать все время по очереди, а сделать в TClient ссылку не только на Next, но и на Prev...

volvo, это больной вопрос sad.gif Они мне снятся уже, эти динамические переменные!!! Я уже не знаю, с какой стороны подойти, чтоб не обжечься...
volvo
Цитата(Jill @ 28.07.2006 13:59)
Это не так, да?
Не так, конечно... Применять или нет Repeat/Until программист должен НЕ там, где используются (или не используются) динамические переменные, а там, где это удобно...

Цитата(Jill @ 28.07.2006 13:59)
Второе - какими кнопками прервать
Иногда помогает Ctrl+Break, но это срабатывает в Турбо-Паскале 7.0 далеко не всегда, а только во время выполнения операций ввода/вывода... В остальное время вряд ли у тебя получится что-то сделать...

Цитата(Jill @ 28.07.2006 13:59)
volvo, это больной вопрос sad.gif Они мне снятся уже, эти динамические переменные!!! Я уже не знаю, с какой стороны подойти, чтоб не обжечься...
Если ты готова пожертвовать 4-мя байтами памяти на каждый элемент очереди, чтобы было проще (и быстрее, насколько я понимаю) работать с этой самой очередью, то добавь ссылку на предыдущий элемент. Если программа критична к использованию памяти, а скорость ее работы менее важна - то этого делать не стОит... А ошибаться не бойся: "Не ошибается только тот, кто ничего не делает" (С)
Jill
Еще вопрос. По поводу вывода требований и течения смоделированного времени +это самое время, правда поединично надо тоже выводить (0,1,2,3,.....10)

Вывод списка требований производится с задержкой, если предыдущий и текущий элемент отличаются:
 if (pred<>NIL)and(pred^.t1<>curr^.t1) then Delay(1000); 


Как обработать данные, чтобы, например, если элементы отличаются на 2 - единицы времени - задержка вывода списка - в два раза больше {с этим вроде разобралась...}, а вывод текущего времени - продолжается? {а вот с этим - нет sad.gif}

Надеюсь, не слишком запутанно...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.