RadBanka
Program EXE Dĺžku
intervalu medzi dvoma príchodmi a tiež dĺžku trvania obsluhy generujeme
pri plánovaní nových udalostí náhodne. Pri tom je však potrebné pozna rozdelenie pravdepodobnosti
príslušných náhodných veličín! Aj keď táto problematika patrí skôr na
hodinu "modelovania a simulácie" a vyžaduje tiež aspoň základné
vedomosti z teórie pravdepodobnosti, aspoň naznačíme spôsob
generovania náhodných číselných postupností v našom programe: - Predpokladáme, že
intervaly medzi príchodmi i dĺžka obsluhy majú tzv. exponenciálne
rozdelenie so strednými hodnotami 75 a 120 sekúnd (zo
zadania).
- Pomocou
rand získame nejaké celé číslo z intervalu 0..RAND_MAX - My však potrebujeme náhodné číslo z intervalu <0, 1). Preto použijeme makro
real_rand - Takto získané náhodné číslo je z tzv. rovnomerného rozdelenia na intervale <0, 1). Musíme ho pomocou funkcie
exp_rand
transformova na náhodné číslo z požadovaného rozdelenia - Okrem toho tiež potrebujeme zabezpeči nezávislos dvoch náhodných číselných postupností. Na to využijeme štandardnú funkciu
srand , ktorá umožňuje nastavi počiatočnú hodnotu generátora. V premenných SeedPrich, SeedObsl
si budeme pamäta pre každú postupnos posledné vygenerované číslo, aby
sme mohli pokračova pri generovaní ďalšieho "tam kde sme skončili". V
hlavnom programe voláme preto podľa potreby jednu z funkcií GenerujDalsiPrichod a GenerujDlzkuObsluhy
/* pripojenie potrebných hlavičkových súborov */
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <math.h>
/* makro */
#define real_rand(cislo) ((double) (cislo)/(RAND_MAX + 1.0));
/* symbolické konštanty - zo zadania */
#define StrPrich 75.0
#define StrObsl 120.0
#define MaxDlzkaRadu 30
/* definícia typov */
typedef enum {
PrichodZakaznika, KoniecObsluhy
} TypUdalosti;
typedef enum {
false, true
} boolean;
typedef struct udalost {
TypUdalosti typ;
double cas;
struct udalost *nasl;
} TUdalost;
/* globálne premenné */
TUdalost *Zac; /* ukazovateľ na začiatok osi */
TUdalost *AktUdal; /* ukazovateľ na aktuálnu udalos? */
TypUdalosti TypAktUdal;
double SimulCas;
/* premenné a funkcie súvisiace s náhodným generovaním */
unsigned SeedObsl, SeedPrich;
double exp_rand(unsigned *Seed, double StrHodnota);
double GenerujDalsiPrichod();
double GenerujDlzkuObsluhy();
---------------------------------------------------------------------------------
void vloz(TUdalost *NovaUdal) /* vloženie novej udalosti na správne miesto */
{
double CasNovej;
TUdalost *p1, *p2;
CasNovej = NovaUdal->cas;
p1 = Zac->nasl;
p2 = Zac;
while (p1->cas <= CasNovej) {
p2 = p1;
p1 = p1->nasl;
}
p2->nasl = NovaUdal;
NovaUdal->nasl = p1;
}
---------------------------------------------------------------------------------
void zrus_os() /* uvoľnenie pamäte po uplynutí simulačného času */
{
TUdalost *p1, *p2;
p1 = Zac->nasl;
while (p1 != Zac) {
p2 = p1;
p1 = p1->nasl;
free((void*)p2);
}
free((void*)Zac);
Zac = NULL;
}
---------------------------------------------------------------------------------
void main() /* hlavný program */
{
int PocZak = 0; /* počet všetkých zákazníkov */
int PocCakZak = 0; /* počet tých, ktorí museli po príchode čaka? */
int PocObslZak = 0; /* počet obslúžených */
int PocOdmietZak = 0; /* počet odmietnutých */
int DlzkaRadu = 0; /* počet ľudí v rade */
double CasCakCelkom = 0.0; /* celkový čas, ktorí museli čaka? všetci zákazníci spolu */
double PredchAktCas = 0.0; /* čas predchádzajúcej udalosti */
double AktCas; /* čas aktuálnej udalosti */
double DeltaCas; /* dĺžka časového intervalu od prechádzajúcej udalosti po aktuálnu */
int ObsluhaVolna = true;
/* vstup */
clrscr();
printf("Simulacny cas (v sekundach): ");
scanf("%lf", &SimulCas);
randomize(); SeedPrich = rand();
randomize(); SeedObsl = rand();
/* konštrukcia prázdnej časovej osi */
Zac = (TUdalost*)malloc(sizeof(TUdalost));
Zac->cas = 1.7E38;
Zac->nasl = Zac;
/* naplánovanie príchodu prvého zákazníka */
AktUdal = (TUdalost*)malloc(sizeof(TUdalost));
AktUdal->typ = PrichodZakaznika;
AktUdal->cas = GenerujDalsiPrichod();
/* vloženie novej udalosti do frontu*/
vloz(AktUdal);
/* simulácia */
do {
AktUdal = Zac->nasl;
Zac->nasl = AktUdal->nasl;
AktCas = AktUdal->cas;
DeltaCas = AktCas - PredchAktCas;
if (DlzkaRadu > 0) CasCakCelkom += DlzkaRadu * DeltaCas;
TypAktUdal = AktUdal->typ;
if (TypAktUdal == PrichodZakaznika) {
if (DlzkaRadu < MaxDlzkaRadu) {
PocZak++;
if (ObsluhaVolna) {
AktUdal->cas += GenerujDlzkuObsluhy();
AktUdal-> typ = KoniecObsluhy;
vloz(AktUdal);
ObsluhaVolna = false;
AktUdal = (TUdalost*)malloc(sizeof(TUdalost));
}
else {
DlzkaRadu++;
PocCakZak++;
}
}
else PocOdmietZak++;
AktUdal->cas = AktCas + GenerujDalsiPrichod();
AktUdal->typ = PrichodZakaznika;
vloz(AktUdal);
}
else { /* koniec obsluhy */
PocObslZak++;
if (DlzkaRadu > 0) {
AktUdal->cas += GenerujDlzkuObsluhy();
AktUdal->typ = KoniecObsluhy;
vloz(AktUdal);
DlzkaRadu--;
}
else {
free((void*)AktUdal);
ObsluhaVolna = true;
}
}
PredchAktCas = AktCas;
} while(Zac->nasl->cas <= SimulCas);
zrus_os();
/* výstup */
clrscr();
printf(" \nV Y S L E D K Y \n\n");
printf("Zakaznik cakal v rade priemerne: ");
printf("%0.4lf s\n", (PocCakZak == 0) ? 0 : CasCakCelkom/PocCakZak);
printf("Priemerna dlzka radu pred okienkom: %0.4lf\n", CasCakCelkom/SimulCas);
printf("Celkovy pocet zakaznikov, ktori prisli do banky: %d\n", PocZak);
printf("Pocet odmietnutych zakaznikov: %d\n", PocOdmietZak);
printf("Pocet skutocne obsluzenych zakaznikov: %d\n", PocObslZak);
getch();
}
---------------------------------------------------------------------------------
double exp_rand(unsigned *Seed, double StrHodnota)
{
srand(*Seed); /* nastavenie poslednej vygenerovanej hodnoty*/
*Seed = rand(); /* ďalšie náhodné číslo */
double cislo = real_rand(*Seed); /* číslo z <0, 1) */
return (-StrHodnota * log(1-cislo)); /* transformácia */
}
/* funkcie zabezpečujúce nezávislos? dvoch postupností náhodných čísel */
double GenerujDalsiPrichod()
{
return(exp_rand(&SeedPrich, StrPrich));
}
double GenerujDlzkuObsluhy()
{
return(exp_rand(&SeedObsl, StrObsl));
}
|