/*****************************************************************************/
/*                待ち行列シミュレータin C  Ver.2.00                         */
/*                             Coded By A.Mimura                             */
/*                                                 (c)Iba Lab.  01.Nov.2001  */
/*  ご注意：                                                                 */
/*　　　   (1)このプログラムは東京大学工学部電気系講義「システム工学基礎」   */
/*　　　　　　における学習用として作成されたものです。                       */
/*         (2)著作権は東京大学工学系研究科伊庭研究室に属すものと             */
/*　　　　　　しますが、研究目的に限り改造は自由とします。                   */
/*         (3)このプログラムに関するご意見・質問は、下記メールアドレスまで。 */
/*　　　　　　　amimura@miv.t.u-tokyo.ac.jp                                  */
/*            バグの報告等をよろしくお願いします。                           */
/*            Windows版ほど機能はなく,シンプルにしてあります。ですから足り   */
/*            ない機能や不具合は自分でなんとかするというスタンスでいてくだ   */
/*            さい。できる限りの対応はしますが。　                           */
/*  使用方法:                                                                */
/*         (1)コンパイルは,                                                  */
/*            gcc Q_Simulation.c -lm                                         */
/*            です。-lm は環境によりますが,なくても通れば問題ないです。      */
/*         (2)出来上がった実行ファイルa.outを実行すると,コンソール           */
/*            からパラメータの入力が求められますので,適切な値を入れて        */
/*            ください。                                                     */
/*         (3)たくさん実験する場合には,(2)は面倒ですので、引数で指定する     */
/*            、ファイルで与えるなど、工夫したものをつくってみては。         */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/*       ヘッダ部分(諸々の事情で一つのファイルにまとめちゃいました)          */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

/*系内客情報を保持する上限*/
#define C_IN_SYS_MAX 100000

/*一人の客が持つ情報*/
struct customer_struct {
       int number;             /*通し番号*/
       int state;              /*状態 -1:待ち行列内
                                     >=0:サービスを受けている窓口番号*/
       double arrival_time;    /*到着時刻*/
       int next;               /*次の客番号*/
} *Cstmr_in_sys[C_IN_SYS_MAX]; /*動的に生成した構造体のポインタを保持する配列*/

typedef struct customer_struct c_struct;
 
int    Srv_mode;       /*サービス分布のモード*/
int    E_r;            /*アーラン到着の次数（位相）*/
int    E_k;            /*アーランサービスの次数（位相）*/
double Lnr_max;        /*一様の時の最大値*/
double Lnr_min;        /*最小値*/
int    Sys_max;        /*系内人数の上限*/
int    Win_n;          /*窓口数*/
double Ramda;          /*到着率*/
double Myu;            /*サービス率*/
double End_t;          /*シミュレーションの終了時刻*/
	
double Rou;            /*トラフィック密度*/
int    Win_vct_n;      /*空き窓口数*/
double Awin_t;         /*全窓口がふさがった時刻*/
double Awin_t_sum;     /*全窓口がふさがった時間の累計*/
int    *Ewin_s;        /*各窓口の空き状況 0:空き or サービス中の客番号*/
double *Ewin_st_t;     /*各窓口のサービス開始時刻*/
double *Ewin_fin_t;    /*各窓口のサービス終了時刻*/
double *Ewin_t_sum;    /*各窓口がふさがっている時間の累計*/

int    Ql;             /*待ち行列長*/
int    Ql_max;         /*最大待ち行列長*/
double Ql_t;           /*現在の待ち行列長になった時刻*/
double Ql_t_sum;       /*待ち行列長*継続時間*/
int    Top_cstmr_n;    /*待ち行列の先頭にいる客番号*/

double Wt_t_sum;       /*待ち時間の累計*/
double Wt_t_max;       /*最大待ち時間*/
int    Sys_cstmr_n;    /*系内人数*/
int    Sys_cstmr_max;  /*最大系内人数*/
double Sys_cstmr_t;    /*現在の系内人数になった時刻*/
double Sys_enp_t_sum;  /*系内人数が0になった時間累計*/
double Sys_cstmr_t_sum;/*系内人数*継続時間*/

double Stay_t_sum;     /*滞在時間の累計*/
double Stay_t_max;     /*最大滞在時間*/

double Nxt_arv_t;      /*次の客の到着時刻*/
double Current_t;      /*現在時刻*/
int    Arv_cstmr_n;    /*到着客数*/
int    Ref_cstmr_n;    /*呼損客数*/

int    rand_val;       /*seedに与える値*/

void customer_init(c_struct *,int,int,double);
void add_customer(c_struct *);
void delete_customer(int);
void change_state(int,int);
int search_top(void);
double search_time(int);

void get_parameter(void);
void check_parameter(void);
void init_parameter(void);
void mainloop(void);
int next_process(void);
void arrival_process(void);
void service_process(int);
void output(void);
void free_parameter();
double get_arv_time(void);
double get_srv_time(void);
double drand48(void);
void set_seed(void);

/*****************************************************************************/
/*                       c_struct関係                                        */
/*****************************************************************************/
/**********************************************/
/*    customer_init()                         */
/*  到着した客のパラメータを初期化            */
/*    in ポインタ, 客番号、客の状態、到着時刻 */
/**********************************************/
void customer_init(c_struct *cstmr,int num,int ste,double a_tim)
{
int i=0;

while(Cstmr_in_sys[i]!=NULL)
 i++;

if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}

  Cstmr_in_sys[i]=cstmr;
  cstmr->number=num;
  cstmr->state=ste;
  cstmr->arrival_time=a_tim;
  cstmr->next=-1;
}

/**********************************************/
/*      add_custmoer()                        */
/*到着した客番号を最後尾のnext_customerに追加 */
/*      in  客ポインタ                        */
/**********************************************/
void add_customer(c_struct *cstmr)
{
int i=0;

while(Cstmr_in_sys[i]->next!=-1)
	i++;
if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}
if(i!=0)
 Cstmr_in_sys[i]->next=cstmr->number;

}

/**********************************************/
/*      delete_custmoer()                     */
/*  帰る客を削除                              */
/*      in  客番号                            */
/**********************************************/
void delete_customer(int num)
{
int j,i=0;

while(Cstmr_in_sys[i]->number!=num)
 i++;
if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}

if(i!=0)
Cstmr_in_sys[i-1]->next=Cstmr_in_sys[i]->number;

free(Cstmr_in_sys[i]);

for(j=i;j<C_IN_SYS_MAX-1 || Cstmr_in_sys[j+1]==NULL;j++){
Cstmr_in_sys[j]=Cstmr_in_sys[j+1];
Cstmr_in_sys[j+1]=NULL;
}

}
/**********************************************/
/*      change_state()                        */
/*  客の状態を変更                            */
/*      in  客番号,状態                       */
/**********************************************/
void change_state(int num,int ste)
{
int i=0;
while(Cstmr_in_sys[i]->number!=num)
  i++;
if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}
Cstmr_in_sys[i]->state=ste;
}

/**********************************************/
/*      search_top()                          */
/*  行列の先頭にいる客を検索                  */
/*   out 客番号                               */
/**********************************************/
int search_top(void)
{
int i=0;
while(Cstmr_in_sys[i]->state !=-1)
  i++;
if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}
return Cstmr_in_sys[i]->number;
}

/**********************************************/
/*      search_time()                         */
/*  客の到着時刻を返す                        */
/*      in  客番号                            */
/*      out 到着時刻                          */
/**********************************************/
double search_time(int num)
{
int i=0;
while(Cstmr_in_sys[i]->number!=num)
 i++;
if(i>=C_IN_SYS_MAX){
	printf("Too Many Customers!!(C_IN_SYS_MAX)\n");
	exit(0);
}
return Cstmr_in_sys[i]->arrival_time;

}


/*****************************************************************************/
/*                          待ち行列処理                                     */
/*****************************************************************************/
/***********************************************/
/*  get_parameter()                            */
/*  コンソールからパラメータを受け取る         */
/***********************************************/
void get_parameter()
{
printf("アーラン到着次数?（1:指数分布）\n");
scanf("%d",&E_r);

printf("サービス分布? 0=アーラン分布,1=一様分布,2=一定分布\n");
scanf("%d",&Srv_mode);

	switch(Srv_mode){
	case 0: 
	        printf("次数?（1:指数分布）\n");
                scanf("%d",&E_k);
                printf("サービス率? (人／単位時間)\n");
		scanf("%lf",&Myu);
	break;
	case 1: 
		printf("サービス率の最大値? (人／単位時間)\n");
		scanf("%lf",&Lnr_max);
		printf("サービス率の最小値? (人／単位時間)\n");
		scanf("%lf",&Lnr_min);
		Myu=(Lnr_min+Lnr_max)/2.0;
	break;
	case 2:
		printf("サービス率? (人／単位時間)\n");
		scanf("%lf",&Myu);
	break;
	}

printf("到着率? (人／単位時間)\n");
scanf("%lf",&Ramda);
printf("窓口数?\n");
scanf("%d",&Win_n);
printf("系内人数の最大値?(-1=無限大)\n");
scanf("%d",&Sys_max);
printf("シミュレーション時間?\n");
scanf("%lf",&End_t);

}

/***********************************************/
/*  受け取ったパラメータの適正をチェック　     */
/***********************************************/
void check_parameter(void)
{
	char p;
 Rou=Ramda/(Myu*Win_n);
 
  while(Rou>1){
	  printf("トラフィック密度が１を超えています(%10.5f)\n",Rou);
	while(p!='n' && p!='y'){
	  printf("パラメータを再設定しますか？(y/n)\n");
	  scanf("%s",&p);
  	}
	if(p=='n')
	  break;
	else if(p=='y'){
	p=' ';  
	get_parameter();
	Rou=Ramda/(Myu*Win_n);
	}

  }


}


/***********************************************/
/*  　　　　　パラメータの初期化　 　　　　    */
/***********************************************/
void init_parameter(void)
{
int i;
	Win_vct_n=Win_n;
	Awin_t=0.0;
	Awin_t_sum=0.0;

	Ql=0;
	Ql_max=0;
	Ql_t=0.0;
	Ql_t_sum=0.0;
	Top_cstmr_n=0;

	Wt_t_sum=0.0;
	Wt_t_max=0.0;
	Sys_cstmr_n=0;
	Sys_cstmr_max=0;
	Sys_cstmr_t=0.0;
	Sys_enp_t_sum=0.0;
	Sys_cstmr_t_sum=0.0;

	Stay_t_sum=0.0;
	Stay_t_max=0.0;

	Nxt_arv_t=get_arv_time();
	Current_t=0.0;
	Arv_cstmr_n=0;
	Sys_cstmr_n=0;
	Ref_cstmr_n=0;

	if((Ewin_s=(int *)malloc(sizeof(int)*Win_n))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	}

	if((Ewin_st_t=(double *)malloc(sizeof(double)*Win_n))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	}

	if((Ewin_fin_t=(double *)malloc(sizeof(double)*Win_n))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	}

	if((Ewin_t_sum=(double *)malloc(sizeof(double)*Win_n))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	}

	for(i=0;i<Win_n;i++){
	Ewin_s[i]=0;
	Ewin_st_t[i]=0.0;
	Ewin_fin_t[i]=0.0;
	Ewin_t_sum[i]=0.0; 
	}

	for(i=0;i<C_IN_SYS_MAX;i++){
	Cstmr_in_sys[i]=NULL;
	}

	set_seed();
	srand(rand_val);

}


/***********************************************/
/*  　　　　シミュレーションを行う 　　　　    */
/***********************************************/
void mainloop()
{
int prcs=0;
printf("process:0=arrival;n=servicing window number;-1=end\n");

	while(prcs >-1){
	  prcs=next_process();
	  if(prcs==0)
		arrival_process();
	  else if(prcs>0)
		service_process(prcs);

	}
}

/***********************************************/
/*  　　next_process()　　　　          　     */
/*      次にする処理を決める                   */
/***********************************************/
int next_process(void)
{
	int i,prcs;
	double t;
	
	prcs=-1;
	t=End_t;

/*客の到着、サービス終了のうちもっとも早くくるものを探す*/	
	if(Nxt_arv_t>0.0 && Nxt_arv_t<=t){
	  prcs=0;
	  t=Nxt_arv_t;
	}
	for(i=0;i<Win_n;i++){
	  if(Ewin_s[i]>0 && Ewin_fin_t[i]<=t){
		prcs=i+1;
		t=Ewin_fin_t[i];
	  }
	}
	if(Current_t>End_t)
	prcs=-1;

/*途中経過を表示 0:到着,-1:終了*/
printf("%d",prcs);
if(prcs==-1)
printf("\n\n");

return prcs;
}

/***********************************************/
/*  　　　　arrival_process()　     　　       */
/*          客の到着に伴う処理                 */
/***********************************************/
void arrival_process(void)
{
int i,j;
c_struct *cstmr;

/*到着客カウンタ*/
Arv_cstmr_n++;
/*現在時刻*/
Current_t=Nxt_arv_t;
/*次の客の到着時刻*/
Nxt_arv_t=Current_t+get_arv_time();

/*系内人数を確認して許容範囲外の客を追い返す*/
if(Sys_max>0 && Sys_max<=Ql+(Win_n-Win_vct_n)){
	Ref_cstmr_n +=1;
        return;
}

/*系内客数*その人数でいた時間*/
Sys_cstmr_t_sum+=(double)(Sys_cstmr_n)*(Current_t-Sys_cstmr_t);
/*系内客数*/
Sys_cstmr_n++;
/*系内人数が0だったとき*/
if(Sys_cstmr_n==1)
Sys_enp_t_sum+=(Current_t-Sys_cstmr_t);
/*最大値*/
if(Sys_cstmr_n>Sys_cstmr_max)
	Sys_cstmr_max=Sys_cstmr_n;
/*現在の系内客数になった時間*/
Sys_cstmr_t=Current_t;

/*窓口に空きがないとき*/
  if(Ql>0 || Win_vct_n==0){
 	if((cstmr=(c_struct *)
            malloc(sizeof(c_struct)))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	}
/*初期パラメータを入れる*/
	customer_init(cstmr,Arv_cstmr_n,-1,Current_t);
/*最後尾の客のnext_customerにわたす*/
	add_customer(cstmr);

	/*待ち行列長*その長さになった時間*/
	Ql_t_sum+=(double)(Ql)*(Current_t-Ql_t);
	/*待ち行列数*/
	Ql++;
	/*最大値*/
	if(Ql>Ql_max)
	Ql_max=Ql;
	/*先頭の客*/
	if(Ql==1)
	Top_cstmr_n=Arv_cstmr_n;
	/*待ち行列時間の更新*/
	Ql_t=Current_t;
  }
/*空きがあるとき*/
  else {    
	j=-1;
	for(i=0;i<Win_n && j<0;i++){
	   if(Ewin_s[i]==0){
		if((cstmr=(c_struct *)
                    malloc(sizeof(c_struct)))==NULL){
		printf("Memory allocation error\n");
		exit(0);
	        }
	   customer_init(cstmr,Arv_cstmr_n,i,Current_t);
	   /*最後尾の客のnext_customerにわたす*/
	   add_customer(cstmr);
	   j=i;
	   /*窓口使用状況*/
	   Ewin_s[j]=Arv_cstmr_n;
	   /*サービス終了時刻*/
	   Ewin_fin_t[j]=Current_t+get_srv_time();
	   /*窓口の空き状況*/
	   Win_vct_n-=1;
	   /*窓口がふさがった時刻*/
	   Ewin_st_t[j]=Current_t;
	   /*全ての窓口がふさがった場合*/
	   if(Win_vct_n==0)
	     Awin_t=Current_t;
	   }
	}
  }

}

/***********************************************/
/*  　　　　service_process()　     　　       */
/*          サービス終了に伴う処理             */
/*         in サービスを終える窓口番号         */
/***********************************************/
void service_process(int wnum)
{
int i;
double tim;

/*番号を1減らす*/
wnum--;
/*現在時刻の設定*/
Current_t=Ewin_fin_t[wnum];
/*系内客数*その時間*/
Sys_cstmr_t_sum+=(double)Sys_cstmr_n*(Current_t-Sys_cstmr_t);
/*系内人数*/
Sys_cstmr_n--;
/*現在の系内人数になった時刻をセット*/
Sys_cstmr_t=Current_t;

/*この客の滞在時間*/
tim=Current_t-search_time(Ewin_s[wnum]);
/*全客の滞在時間の累計*/
Stay_t_sum+=tim;
/*一人の客の最大滞在時間*/
if(tim>Stay_t_max)
Stay_t_max=tim;
/*客の削除*/
delete_customer(Ewin_s[wnum]);

/*窓口の空き*/
Win_vct_n++;
Ewin_s[wnum]=0;
/*窓口がふさがっている時間の累計*/
Ewin_t_sum[wnum]+=(Current_t-Ewin_st_t[wnum]);

/*待ち行列がある場合の処理*/
if(Ql>0){
Win_vct_n--;
/*待ち行列長*その継続時間:バグってました*/
Ql_t_sum+=(double)Ql*(Current_t-Ql_t);
/*待ち行列長*/
Ql--;
/*新しい待ち行列長になった時間*/
Ql_t=Current_t;
/*待ち時間の累計*/
tim=(Current_t-search_time(Top_cstmr_n));
Wt_t_sum+=tim;
/*最大待ち時間*/
if(tim>Wt_t_max)
Wt_t_max=tim;

/*次の客を窓口にわたす*/
wnum=-1;
  for(i=0;i<Win_n && wnum<0;i++){
	if(Ewin_s[i]==0){
	   wnum=i;
	   Ewin_s[wnum]=Top_cstmr_n;
	   Ewin_fin_t[wnum]=Current_t+get_srv_time();
	   Ewin_st_t[wnum]=Current_t;
	   change_state(Top_cstmr_n,wnum);
	}
  }
/*行列の先頭にいる客番号を得る*/
  if(Ql>0)
	Top_cstmr_n=search_top();

}

/*待ち行列がない場合の処理*/
  else {
	if(Win_vct_n==1)
	   Awin_t_sum+=(Current_t-Awin_t);
  }
}
/***********************************************/
/*  　　　　　　　結果を出力する　　　　　     */
/***********************************************/

void output(void)
{
	int i,n;
	double L, Lq, p0, pi, ram, rn, rou, rs, W, Wq, Ref;
        double kai=1.0;
        double kai2=1.0;
        double sig=1.0;
        double sig2=0.0;
        char* srv;
        char* arv;
        char* win;

	rn  = (double)Arv_cstmr_n;
	rs  = (double)Win_n;

        Rou = Ramda/(Win_n*Myu);
         if(Rou==1.00)
            Rou=1.0000001;
        rou = Ramda/ Myu;
         if(rou==1.00)
            rou=1.0000001;

/*客がこなかった*/
        if(Arv_cstmr_n==0){
         printf("来客数=0です！！パラメータを変えてください\n");
         return;
        }

/*各窓口使用状況を調べる*/
        for(i=0 ; i<Win_n ; i++){
                if(Ewin_s[i]>0)
                  Ewin_t_sum[i] += (Current_t-Ewin_st_t[i]);
        }

        if(Win_vct_n==0)
                Awin_t_sum += (Current_t-Awin_t);

//***************************理論値を計算 ****************************//

   if(E_r==1 && Srv_mode==0 && E_k==1 && Rou<1.0){   //　M/M/ｓのばあい
	if (Win_n == 1) {
//************** M/M/1(∞) ***************//
              if(Sys_max==-1){
                  /*系内に0人の確率*/
		  p0 = 1.0 - rou;
                  /*窓口の閉塞率*/
                  pi = rou;
		  /*平均系内客数 E(n)*/
                  L = rou/(1.0-rou);
                  /*平均待ち行列長 E(m)*/
                  Lq = L*rou;
                  /*平均滞在時間  E(v)*/
                  W = 1.0/(Myu-Ramda);
                  /*平均待ち時間  E(w)*/
                  Wq = W*rou;
              }

//*************** M/M/1(N) ****************//
              else {
                  double tmp=pow(rou,Sys_max);
                  p0 = (1.0-rou)/(1.0-tmp*rou);
                  L  = rou*(1.0-(Sys_max+1.0)*tmp+Sys_max*tmp*rou)/((1.0-rou)*(1.0-tmp*rou));
                  Lq = L-(1.0-p0);
                  W  = 1.0/(Myu-Ramda);
                  Wq = W*rou;
                  Ref= p0*rou;
              }

	}
	else {
                for(n=1;n<Win_n;n++){
                   kai *=n;
                   sig +=pow(rou,n)/kai;

                }
//**************** M/M/s(∞) *****************//
              if(Sys_max==-1){
                p0 = sig+pow(rou,rs)/(kai*(rs-rou));
                p0 = 1.0/p0;
                pi = p0*pow(rou,rs)/(kai*(rs-rou));
                L  = pi*rou/(rs-rou)+rou;
                Lq = L-rou;
                W  = L/Ramda;
                Wq = Lq/Ramda;
               }

//***************** M/M/s(N) ******************//
              else {
                for(n=Win_n+1;n<=Sys_max;n++){
                   sig2 += pow((rou/Win_n),n);
                }
                kai = kai*Win_n;
                sig += pow(rou,Win_n)/kai;

                p0 = 1.0/(sig+pow(Win_n,Win_n)*sig2/kai);

                L =0.0;
                for(n=1;n<Win_n;n++){
                   kai2 *= n;
                   L += n*p0*pow(rou,n)/kai2;
                }
                for(n=Win_n;n<=Sys_max;n++){
                   L += n*p0*pow(rou,n)/(kai*pow(Win_n,n-Win_n));
                }
                Lq=0.0;
                for(n=Win_n+1;n<=Sys_max;n++){
                   Lq += (n-Win_n)*p0*pow(rou,n)/(kai*pow(Win_n,n-Win_n));
                }
                W = L/Ramda;
                Wq = Lq/Ramda;
                Ref= p0*pow(rou,Sys_max)/(kai*pow(Win_n,Sys_max-Win_n));
              }

	}
   }
//***************** M/Ek/1(∞)*****************//
   else if(E_r==1 && Srv_mode==0 && E_k>1 && Rou<1.0 && Win_n==1 && Sys_max==-1){
                Lq  = (E_k+1)*Ramda*Ramda/(2.0*E_k*Myu*(Myu-Ramda));
                L = Lq+rou;
                Wq  = Lq/Ramda;
                W = Wq+1.0/Myu;
   }
//***************** M/D/1(∞) *****************//
   else if(E_r==1 && Srv_mode==2 && Rou<1.0 && Win_n==1 && Sys_max==-1){
                L  = rou*(2.0-rou)/(2.0*(1.0-rou));
                Lq = L*rou/(2.0*(2.0-rou));
                W  = L/(rou*Myu);
                Wq = W*rou/(2.0-rou);
        }


//*****************************以下結果表示****************************//
printf("*************************RESULTS************************\n");

if(Sys_max==-1)
  win="s(∞)";
else
  win="s(N)";
if(E_r==1)
  arv="M/";
else
  arv="Er/";
switch(Srv_mode){
case 0:
  if(E_k==1)
   srv="Ek/";
  else
   srv="M/";;
break;
case 1:
  srv="GI/";
break;
case 2:
  srv="D/";
break;
}
printf("モデル                =%s%s%s\n",arv,srv,win);

printf("シミュレーション時間  =%10.5f\n",Current_t);
printf("総来客数(人)          =%4d\n",Arv_cstmr_n);
printf("トラフィック密度      =%10.5f\n",Rou);

printf("系内人数0の確率(％)   =%10.5f",Sys_enp_t_sum/Current_t*100);
/*M/M/s(*) */
if(E_r==1 && Srv_mode==0 && E_k==1 && Rou<1)
printf("  (理論値 =%10.5f)",p0*100);
printf("\n");

/* M/?/s(N) */
if(Sys_max!=-1)
printf("呼損率(％)            =%10.5f",(double)Ref_cstmr_n/(double)Arv_cstmr_n*100);
/* M/M/s(N) */
if(E_r==1 && Srv_mode==0 && E_k==1 && Rou<1 && Sys_max!=-1)
printf("  (理論値 =%10.5f)",Ref*100);
printf("\n");

printf("\n");
/*全て*/
printf("全窓口の閉塞率(％)    =%10.5f",Awin_t_sum/Current_t*100);
/* M/M/s(∞) */
if(E_r ==1 && Srv_mode==0 && E_k==1 && Rou<1 && Sys_max==-1)
printf("  (理論値 =%10.5f)",pi*100);
printf("\n");

/**/
for(i=0;i<Win_n;i++){
printf("窓口 %d の閉塞率(％)   =%10.5f\n",i+1,Ewin_t_sum[i]/Current_t*100);
}
printf("\n");
printf("平均待ち行列長(人)    =%10.5f",Ql_t_sum/Current_t);

/* M/M/s(*)  M/D/1(∞) M/Ek/1(∞)*/
if((E_r==1 && Srv_mode==0 && E_k==1 && Rou<1) 
|| (E_r==1 && Srv_mode==2 && Rou<1 && Win_n==1 && Sys_max==-1)
|| (E_r==1 && Srv_mode==0 && E_r>1 && Win_n==1 && Sys_max==1))
printf("  (理論値 =%10.5f)",Lq);
printf("\n");

/*全て*/
printf("最大待ち行列長(人)    =%4d\n",Ql_max);

printf("平均系内客数(人)      =%10.5f",Sys_cstmr_t_sum/Current_t);
/* M/M/s(*)  M/D/1(∞) M/Ek/1(∞)*/
if((E_r==1 && Srv_mode==0 && E_k==1 && Rou<1) 
|| (E_r==1 && Srv_mode==2 && Rou<1 && Win_n==1 && Sys_max==-1)
|| (E_r==1 && Srv_mode==0 && E_r>1 && Win_n==1 && Sys_max==1))
printf("  (理論値 =%10.5f)",L);
printf("\n");

/* 全て */
printf("最大系内客数(人)      =%4d\n",Sys_cstmr_max);

printf("平均待ち時間          =%10.5f",Wt_t_sum/rn);
/* M/M/s(*)  M/D/1(∞) M/Ek/1(∞)*/
if((E_r==1 && Srv_mode==0 && E_k==1 && Rou<1) 
|| (E_r==1 && Srv_mode==2 && Rou<1 && Win_n==1 && Sys_max==-1)
|| (E_r==1 && Srv_mode==0 && E_r>1 && Win_n==1 && Sys_max==1))
printf("  (理論値 =%10.5f)",Wq);
printf("\n");

/* 全て */
printf("最大待ち時間          =%10.5f\n",Wt_t_max);

printf("平均滞在時間          =%10.5f",Stay_t_sum/rn);
/* M/M/s(*)  M/D/1(∞) M/Ek/1(∞)*/
if((E_r==1 && Srv_mode==0 && E_k==1 && Rou<1) 
|| (E_r==1 && Srv_mode==2 && Rou<1 && Win_n==1 && Sys_max==-1)
|| (E_r==1 && Srv_mode==0 && E_r>1 && Win_n==1 && Sys_max==1))
printf("  (理論値 =%10.5f)",W);
printf("\n");

/* 全て */
printf("最大滞在時間          =%10.5f\n",Stay_t_max);
printf("\n");

printf("********************************************************\n\n");
}


/***********************************************/
/*  　　　　　　   後処理　　       　　　     */
/***********************************************/

void free_parameter(void)
{

int i;

free(Ewin_s);
free(Ewin_st_t);
free(Ewin_fin_t);
free(Ewin_t_sum);

  for(i=0;i<C_IN_SYS_MAX;i++){
     free(Cstmr_in_sys[i]);
  }
}



/***********************************************/
/*  　　get_arv_time()　　          　　　     */
/*         次の客の到着時間を返す              */
/***********************************************/
double get_arv_time(void)
{
  int i;
  double tmp=1.0;
   for(i=0;i<E_r;i++)
    tmp*=drand48();
  return -(1.0/(Ramda*E_r))*log(tmp);
}

/***********************************************/
/*  　　get_srv_time()　　　          　　     */
/*      サービス時間を返す                     */
/***********************************************/
double get_srv_time(void)
{
  double time;
  double tmp=1.0;
  int i;

  switch(Srv_mode){
    case 0:
          for(i=0;i<E_k;i++)
           tmp*=drand48();
          time= -(1.0/(Myu*E_k))*log(tmp);
    break;
    case 1:
          time= 1.0/Lnr_max+(1.0/Lnr_min-1.0/Lnr_max)*drand48();
    break;
    case 2:
          time= 1.0/Myu;
    break;
  }
  return time;
}


/*****************************************************************************/
/*                          メイン部分                                       */
/*****************************************************************************/


/**********************************************/
/*            (0,1)区間の一様乱数             */
/**********************************************/
double drand48(void)
{
double d;
/*乱数生成*/
while((d=(double)rand()/RAND_MAX)==0.0
/*処理時間等があまり大きくならないためのフィルタ*/
/*必要に応じて値を変えて使ってください。        */  
/*                    || d>0.99                 */
);

return d;

}


/**********************************************/
/*             seedの取得                     */
/**********************************************/
void set_seed(void)
{ /*rand_valを得るためのおまじない*/
rand_val=1664525L*rand_val+1013904223L;
rand_val&= 0x7FFFFFFF;
printf("seed:%d\n",rand_val);
}
/**********************************************/
/*              メインルーチン                */
/**********************************************/

int main(void)
{
  int quit_flag=0;
  time_t tt;

  tt=time(NULL);
  rand_val=(0xFFFFFFFF & tt);
  rand_val=1664525L*rand_val+1013904223L;
  rand_val&= 0x7FFFFFFF;

  while(!quit_flag){
	get_parameter();
	check_parameter();
	init_parameter();
	mainloop();
	output();
	free_parameter();
	quit_flag=quit_or_not();
  }
return 0;
}


/***********************************************/
/*  　　　　　終了かどうかを聞く　　　　　     */
/***********************************************/
int quit_or_not(void){
int flag=1;
char p=' ';

while(p!='n' && p!='y'){
	  printf("続けますか？(y/n)\n");
	  scanf("%s",&p);
  	}
if(p=='y')flag=0;
else flag=1;

return flag;

}







