情報学部 | 菅沼ホーム | 目次 | 索引 |
/******************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /******************************/ #include <stdio.h> #include <stdlib.h> #include <ctime> #include <math.h> #include <map> #include <queue> #include "MT.h" using namespace std; /************************/ /* クラスCustomerの定義 */ /************************/ class Customer { public : double time; // 到着時刻 int state; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 /*********************/ /* コンストラクタ */ /* s : 状態 */ /* t : 到着時刻 */ /*******************************/ Customer::Customer(int s, double t) { time = t; state = s; } }; /**********************/ /* クラスQ_baseの定義 */ /**********************/ class Q_base { int s; // 窓口の数 int asb; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている int *sb; // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 double asb_t; // すべての窓口がふさがった時刻 double c_asb; // すべての窓口がふさがっている時間の累計 double *c_sb; // 各窓口がふさがっている時間の累計 double *st_e; // 各窓口のサービス終了時刻 double *st_s; // 各窓口がふさがった時刻 int m_lq; // 最大待ち行列長 double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計 double c_wt; // 待ち時間の累計 double lq_t; // 現在の待ち行列長になった時刻 double m_wt; // 最大待ち時間 double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計 double c_sys; // 滞在時間の累計 double m_sys; // 最大滞在時間 double sc_t; // 現在の系内客数になった時刻 int m_sc; // 最大系内客数 double m_a; // 到着時間間隔の平均値 double m_s; // サービス時間の平均値 double at; // 次の客の到着時刻(負の時は,終了) double p_time; // 現在時刻 double end; // シミュレーション終了時刻 int nc; // 到着客数カウンタ map<int, Customer> cus; // 系内にいる客のリスト queue<int> que; // 待ち行列 public: Q_base(int, double, double, double); // コンストラクタ ~Q_base(); // デストラクタ double Next_at(); // 次の到着時刻 double Next_sv(); // サービス終了時刻 void Control(); // 全体の制御 int Next(); // 次の処理の決定 int End_o_s(); // 終了処理 void Arrive(); // 客の到着処理 void Service(int); // サービス終了 void Output(); // 出力 }; /*****************************************/ /* コンストラクタ */ /* s_i : 窓口の数 */ /* m_a_i : 到着時間間隔の平均値 */ /* m_s_i : サービス時間の平均値 */ /* end_i : シミュレーション終了時刻 */ /*****************************************/ Q_base::Q_base (int s_i, double m_a_i, double m_s_i, double end_i) { /* 設定 */ s = s_i; m_a = m_a_i; m_s = m_s_i; end = end_i; /* 領域の確保 */ sb = new int [s]; c_sb = new double [s]; st_e = new double [s]; st_s = new double [s]; for (int i1 = 0; i1 < s; i1++) { sb[i1] = 0; c_sb[i1] = 0.0; } /* 初期設定 */ p_time = 0.0; nc = 0; asb = s; m_lq = 0; m_sc = 0; c_asb = 0.0; c_wt = 0.0; m_wt = 0.0; c_lq_t = 0.0; lq_t = 0.0; m_sys = 0.0; c_sys = 0.0; c_sc_t = 0.0; sc_t = 0.0; /* 乱数の初期設定 */ init_genrand((unsigned)time(NULL)); /* 最初の客の到着時刻の設定 */ at = p_time + Next_at(); } /****************/ /* デストラクタ */ /****************/ Q_base::~Q_base() { delete [] sb; delete [] c_sb; delete [] st_e; delete [] st_s; } /********************************/ /* 次の客の到着までの時間の発生 */ /********************************/ double Q_base::Next_at() { return -m_a * log(genrand_real3()); } /************************/ /* サービス時間の発生 */ /************************/ double Q_base::Next_sv() { return -m_s * log(genrand_real3()); } /**************/ /* 全体の制御 */ /**************/ void Q_base::Control() { int sw = 0; while (sw > -2) { sw = Next(); // 次の処理の選択 if (sw == -1) sw = End_o_s(); // シミュレーションの終了 else { if (sw == 0) Arrive(); // 客の到着処理 else Service(sw); // サービスの終了 } } } /**************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /**************************************************/ int Q_base::Next() { int sw = -1; double t = end; // シミュレーション終了時刻で初期設定 // 次の客の到着時刻 if (at >= 0.0 && at < t) { sw = 0; t = at; } // サービス終了時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0 && st_e[i1] <= t) { sw = i1 + 1; t = st_e[i1]; // 窓口i1のサービス終了時刻 } } return sw; } /**********************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**********************************/ int Q_base::End_o_s() { int sw = -2; p_time = end; // 現在時刻 at = -1.0; // 次の客の到着時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0) { // サービス中の客はいるか? if (sw == -2) { sw = -1; end = st_e[i1]; // 窓口i1のサービス終了時刻 } else { if (st_e[i1] > end) end = st_e[i1]; // 窓口i1のサービス終了時刻 } } } return sw; } /****************/ /* 客の到着処理 */ /****************/ void Q_base::Arrive() { /* 客数の増加と次の客の到着時刻の設定 */ nc += 1; // 到着客数カウンタ p_time = at; // 現在時刻 at = p_time + Next_at(); // 次の客の到着時刻 if (at >= end) at = -1.0; /* 系内客数の処理 */ c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 if ((int)cus.size()+1 > m_sc) m_sc = cus.size() + 1; // 最大系内客数 /* 窓口に空きがない場合 */ if (asb == 0) { Customer ct_p(-1, p_time); cus.insert(pair<int, Customer>(nc, ct_p)); // 客の登録(系内客数) c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 que.push(nc); // 客の登録(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 if ((int)que.size() > m_lq) m_lq = que.size(); // 最大待ち行列長 } /* すぐサービスを受けられる場合 */ else { int k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { Customer ct_p(i1, p_time); cus.insert(pair<int, Customer>(nc, ct_p)); // 客の登録(系内客数) k = i1; sb[k] = nc; // サービスを受けている客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 asb -= 1; // 空いている窓口数 } } st_s[k] = p_time; // 窓口kがふさがった時刻 if (asb == 0) asb_t = p_time; // すべての窓口がふさがった時刻 } } /*********************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /*********************************/ void Q_base::Service(int k) { /* 時間の設定 */ k -= 1; p_time = st_e[k]; // 現在時刻 st_e[k] = -1.0; // サービス終了時間 /* 系内客数の処理 */ c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 /* 滞在時間の処理 */ map<int, Customer>::iterator it = cus.find(sb[k]); double x1 = p_time - (it->second).time; c_sys += x1; // 滞在時間の累計 if (x1 > m_sys) m_sys = x1; // 最大滞在時間 cus.erase(sb[k]); // 客の削除(系内客数) /* 窓口使用時間の処理 */ asb += 1; // 空いている窓口数 sb[k] = 0; // 窓口kを空き状態にする c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計 /* 待ち行列がある場合 */ if (que.size() > 0) { asb -= 1; // 開いている窓口数 c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 int n = que.front(); que.pop(); // 客の削除(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 it = cus.find(n); x1 = p_time - (it->second).time; c_wt += x1; // 待ち時間の累計 if (x1 > m_wt) m_wt = x1; // 最大待ち時間 int k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { k = i1; sb[k] = n; // 窓口kの客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 st_s[k] = p_time; // 窓口kがふさがった時刻 (it->second).state = k; // 客の状態変更 } } } /* 待ち行列がない場合 */ else { if (asb == 1) c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計 } } /************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /************************/ void Q_base::Output() { double rn = (double)nc; double rs = (double)s; double ram = 1.0 / m_a; double myu = 1.0 / m_s; double rou = ram / (rs * myu); double p0, pi; if (s == 1) { p0 = 1.0 - rou; pi = rou; } else { p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))); pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)); } double Lq = pi * rou / (1.0 - rou); double L = Lq + rs * rou; double Wq = Lq / ram; double W = Wq + 1.0 / myu; printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n", p_time, nc, rou, p0); printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n", c_asb/p_time, pi); printf(" 各窓口が塞がっている割合\n"); for (int i1 = 0; i1 < s; i1++) printf(" %d %.3f\n", i1+1, c_sb[i1]/p_time); printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n", c_lq_t/p_time, Lq, m_lq); printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n", c_sc_t/p_time, L, m_sc); printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n", c_wt/rn, Wq, m_wt); printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n", c_sys/rn, W, m_sys); } /****************/ /* main program */ /****************/ int main() { int s; double end, m_a, m_s; /* 入力データ */ printf("窓口の数は? "); scanf("%d", &s); printf("シミュレーション終了時間? "); scanf("%lf", &end); printf(" 到着時間間隔の平均値は? "); scanf("%lf", &m_a); printf(" サービス時間の平均値は? "); scanf("%lf", &m_s); /* システムの定義 */ Q_base base(s, m_a, m_s, end); /* シミュレーションの実行 */ base.Control(); /* 出力 */ base.Output(); return 0; } //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include<stdio.h>" // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" /* // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti<MT_N; mti++) { mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk<MT_N-MT_M;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk<MT_N-1;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */
/******************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /******************************/ import java.io.*; import java.util.*; public class Test { /****************/ /* main program */ /****************/ public static void main(String args[]) throws IOException { int s; double end, m_a, m_s; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); /* 入力データ */ System.out.print("窓口の数は? "); s = Integer.parseInt(in.readLine()); System.out.print("シミュレーション終了時間? "); end = Double.parseDouble(in.readLine()); System.out.print(" 到着時間間隔の平均値は? "); m_a = Double.parseDouble(in.readLine()); System.out.print(" サービス時間の平均値は? "); m_s = Double.parseDouble(in.readLine()); /* システムの定義 */ Q_base base = new Q_base(s, m_a, m_s, end); /* シミュレーションの実行 */ base.Control(); /* 出力 */ base.Output(); } } /**********************/ /* クラスQ_baseの定義 */ /**********************/ class Q_base { private int s; // 窓口の数 private int asb; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている private int [] sb; // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 private double asb_t; // すべての窓口がふさがった時間 private double c_asb; // すべての窓口がふさがっている時間の累計 private double [] c_sb; // 各窓口がふさがっている時間の累計 private double [] st_e; // 各窓口のサービス終了時間 private double [] st_s; // 各窓口がふさがった時間 private int m_lq; // 最大待ち行列長 private double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計 private double c_wt; // 待ち時間の累計 private double lq_t; // 現在の待ち行列長になった時間 private double m_wt; // 最大待ち時間 private double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計 private double c_sys; // 滞在時間の累計 private double m_sys; // 最大滞在時間 private double sc_t; // 現在の系内客数になった時間 private int m_sc; // 最大系内客数 private double m_a; // 到着時間間隔の平均値 private double m_s; // サービス時間の平均値 private double at; // 次の客の到着時間(負の時は,終了) private double p_time; // 現在時間 private double end; // シミュレーション終了時間 private int nc; // 到着客数カウンタ private Random rn; // 乱数 private TreeMap <Integer, Customer> cus; // 系内にいる客のリスト private ArrayDeque <Integer> que; // 待ち行列 /*****************************************/ /* コンストラクタ */ /* s_i : 窓口の数 */ /* m_a_i : 到着時間間隔の平均値 */ /* m_s_i : サービス時間の平均値 */ /* end_i : シミュレーション終了時間 */ /*****************************************/ Q_base (int s_i, double m_a_i, double m_s_i, double end_i) { /* 設定 */ s = s_i; m_a = m_a_i; m_s = m_s_i; end = end_i; /* 領域の確保 */ sb = new int [s]; c_sb = new double [s]; st_e = new double [s]; st_s = new double [s]; for (int i1 = 0; i1 < s; i1++) { sb[i1] = 0; c_sb[i1] = 0.0; } cus = new TreeMap <Integer, Customer> (); que = new ArrayDeque <Integer> (); /* 初期設定 */ p_time = 0.0; nc = 0; asb = s; m_lq = 0; m_sc = 0; c_asb = 0.0; c_wt = 0.0; m_wt = 0.0; c_lq_t = 0.0; lq_t = 0.0; m_sys = 0.0; c_sys = 0.0; c_sc_t = 0.0; sc_t = 0.0; /* 乱数の初期設定 */ rn = new Random(); /* 最初の客の到着時間の設定 */ at = p_time + Next_at(); } /**********************************/ /* 次の客の到着までの時間の発生 */ /**********************************/ double Next_at() { return -m_a * Math.log(rn.nextDouble()); } /************************/ /* サービス時間の発生 */ /************************/ double Next_sv() { return -m_s * Math.log(rn.nextDouble()); } /**************/ /* 全体の制御 */ /**************/ void Control() { int sw = 0; while (sw > -2) { sw = Next(); // 次の処理の選択 if (sw == -1) sw = End_o_s(); // シミュレーションの終了 else { if (sw == 0) Arrive(); // 客の到着処理 else Service(sw); // サービスの終了 } } } /**************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /**************************************************/ int Next() { int sw = -1; double t = end; // シミュレーション終了時刻で初期設定 // 次の客の到着時刻 if (at >= 0.0 && at < t) { sw = 0; t = at; } // サービス終了時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0 && st_e[i1] <= t) { sw = i1 + 1; t = st_e[i1]; // 窓口i1のサービス終了時刻 } } return sw; } /**********************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**********************************/ int End_o_s() { int sw = -2; p_time = end; // 現在時刻 at = -1.0; // 次の客の到着時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0) { // サービス中の客はいるか? if (sw == -2) { sw = -1; end = st_e[i1]; // 窓口i1のサービス終了時刻 } else { if (st_e[i1] > end) end = st_e[i1]; // 窓口i1のサービス終了時刻 } } } return sw; } /****************************/ /* 客の到着処理 */ /* ct : 客リストの先頭 */ /****************************/ void Arrive() { /* 客数の増加と次の客の到着時刻の設定 */ nc += 1; // 到着客数カウンタ p_time = at; // 現在時刻 at = p_time + Next_at(); // 次の客の到着時刻 if (at >= end) at = -1.0; /* 系内客数の処理 */ c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 if (cus.size()+1 > m_sc) m_sc = cus.size() + 1; // 最大系内客数 /* 窓口に空きがない場合 */ if (asb == 0) { Customer ct_p = new Customer(-1, p_time); cus.put(new Integer(nc), ct_p); // 客の登録(系内客数) c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 que.add(new Integer(nc)); // 客の登録(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 if (que.size() > m_lq) m_lq = que.size(); // 最大待ち行列長 } /* すぐサービスを受けられる場合 */ else { int k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { Customer ct_p = new Customer(i1, p_time); cus.put(new Integer(nc), ct_p); // 客の登録(系内客数) k = i1; sb[k] = nc; // サービスを受けている客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 asb -= 1; // 空いている窓口数 } } st_s[k] = p_time; // 窓口kがふさがった時刻 if (asb == 0) asb_t = p_time; // すべての窓口がふさがった時刻 } } /*********************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /* ct : 客リストの先頭 */ /*********************************/ void Service(int k) { /* 時間の設定 */ k -= 1; p_time = st_e[k]; // 現在時刻 st_e[k] = -1.0; // サービス終了時間 /* 系内客数の処理 */ c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 /* 滞在時間の処理 */ Customer ct = cus.get(new Integer(sb[k])); double x1 = p_time - ct.time; c_sys += x1; // 滞在時間の累計 if (x1 > m_sys) m_sys = x1; // 最大滞在時間 cus.remove(new Integer(sb[k])); // 客の削除(系内客数) /* 窓口使用時間の処理 */ asb += 1; // 空いている窓口数 sb[k] = 0; // 窓口kを空き状態にする c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計 /* 待ち行列がある場合 */ if (que.size() > 0) { asb -= 1; // 開いている窓口数 c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 int n = que.pollFirst().intValue(); // 客の削除(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 ct = cus.get(new Integer(n)); x1 = p_time - ct.time; c_wt += x1; // 待ち時間の累計 if (x1 > m_wt) m_wt = x1; // 最大待ち時間 k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { k = i1; sb[k] = n; // 窓口kの客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 st_s[k] = p_time; // 窓口kがふさがった時刻 ct.state = k; // 客の状態変更 } } } /* 待ち行列がない場合 */ else { if (asb == 1) c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計 } } /************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /************************/ void Output() { double rn = (double)nc; double rs = (double)s; double ram = 1.0 / m_a; double myu = 1.0 / m_s; double rou = ram / (rs * myu); double p0, pi; if (s == 1) { p0 = 1.0 - rou; pi = rou; } else { p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))); pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)); } double Lq = pi * rou / (1.0 - rou); double L = Lq + rs * rou; double Wq = Lq / ram; double W = Wq + 1.0 / myu; System.out.printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n", p_time, nc, rou, p0); System.out.printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n", c_asb/p_time, pi); System.out.printf(" 各窓口が塞がっている割合\n"); for (int i1 = 0; i1 < s; i1++) System.out.printf(" %d %.3f\n", i1+1, c_sb[i1]/p_time); System.out.printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n", c_lq_t/p_time, Lq, m_lq); System.out.printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n", c_sc_t/p_time, L, m_sc); System.out.printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n", c_wt/rn, Wq, m_wt); System.out.printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n", c_sys/rn, W, m_sys); } } /************************/ /* クラスCustomerの定義 */ /************************/ class Customer { double time; // 到着時刻 int state; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 /*******************/ /* コンストラクタ */ /* n : 客番号 */ /* s : 状態 */ /*******************/ Customer (int s, double t) { time = t; state = s; } }
test.html
<!DOCTYPE HTML> <HTML> <HEAD> <TITLE>簡単な待ち行列</TITLE> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8"> <SCRIPT TYPE="text/javascript" SRC="simple.js"></SCRIPT> </HEAD> <BODY STYLE="font-size: 130%; background-color: #eeffee;"> <H2 STYLE="text-align:center"><B>簡単な待ち行列</B></H2> <DIV STYLE="text-align:center"> 窓口の数:<INPUT ID="s" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="2"> シミュレーション時間:<INPUT ID="end" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="10000"><BR><BR> 平均到着時間間隔:<INPUT ID="m_a" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="5"> 平均サービス時間:<INPUT ID="m_s" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="4"><BR><BR> <BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON> 結果は下<BR> <TEXTAREA ID="res" COLS="60" ROWS="15" STYLE="font-size: 100%"></TEXTAREA> </DIV> </BODY> </HTML>
simple.js
/******************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /******************************/ base = null; cus = new Array(); que = new Array(); /****************/ /* main program */ /****************/ function main() { cus.splice(0); // 系内にいる客のリスト que.splice(0); // Queueオブジェクトリスト /* 入力データ */ let s = parseInt(document.getElementById("s").value); // 窓口の数 let end = parseFloat(document.getElementById("end").value); // シミュレーション終了時間 let m_a = parseFloat(document.getElementById("m_a").value); // 平均到着時間間隔 let m_s = parseFloat(document.getElementById("m_s").value); // 平均サービス時間 /* システムの定義 */ base = new Q_base(s, m_a, m_s, end); base.at = base.p_time + base.Next_at(); // 最初の客の到着時間 /* シミュレーションの実行 */ base.Control(); /* 出力 */ base.Output(); } /******************************/ /* Customerオブジェクトの定義 */ /******************************/ function Customer(n, s, t) { this.time = t; // 到着時刻 this.num = n; // 客番号 this.state = s; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 return this; } /**********************/ /* Q_baseオブジェクト */ /**********************/ function Q_base(s, m_a, m_s, end) { /* 入力データの設定 */ this.s = s; // 窓口の数 this.m_a = m_a; // 到着時間間隔の平均値 this.m_s = m_s; // サービス時間の平均値 this.end = end; // シミュレーション終了時刻 /* 初期設定 */ this.asb = s; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている this.sb = new Array(); // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 this.c_sb = new Array(); // 各窓口がふさがっている時間の累計 this.st_e = new Array(); // 各窓口のサービス終了時刻 this.st_s = new Array(); // 各窓口がふさがった時刻 for (let i1 = 0; i1 < this.s; i1++) { this.sb[i1] = 0; this.c_sb[i1] = 0.0; } this.asb_t; // すべての窓口がふさがった時刻 this.c_asb = 0.0; // すべての窓口がふさがっている時間の累計 this.m_lq = 0; // 最大待ち行列長 this.c_lq_t = 0.0; // 待ち行列長にその長さが継続した時間を乗じた値の累計 this.c_wt = 0.0; // 待ち時間の累計 this.lq_t = 0.0; // 現在の待ち行列長になった時刻 this.m_wt = 0.0; // 最大待ち時間 this.c_sc_t = 0.0; // 系内客数にその数が継続した時間を乗じた値の累計 this.c_sys = 0.0; // 滞在時間の累計 this.m_sys = 0.0; // 最大滞在時間 this.sc_t = 0.0; // 現在の系内客数になった時刻 this.m_sc = 0; // 最大系内客数 this.at; // 次の客の到着時刻(負の時は,終了) this.p_time = 0.0; // 現在時刻 this.nc = 0; // 到着客数カウンタ return this; } /********************************/ /* 次の客の到着までの時間の発生 */ /********************************/ Q_base.prototype.Next_at = function() { return -base.m_a * Math.log(Math.random()); } /**********************/ /* サービス時間の発生 */ /**********************/ Q_base.prototype.Next_sv = function() { return -base.m_s * Math.log(Math.random()); } /**************/ /* 全体の制御 */ /**************/ Q_base.prototype.Control = function() { let sw = 0; while (sw > -2) { sw = base.Next(); // 次の処理の選択 if (sw == -1) sw = base.End_o_s(); // シミュレーションの終了 else { if (sw == 0) base.Arrive(); // 客の到着処理 else base.Service(sw); // サービスの終了 } } } /**************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /**************************************************/ Q_base.prototype.Next = function() { let sw = -1; let t = base.end; // シミュレーション終了時刻で初期設定 // 次の客の到着時刻 if (base.at >= 0.0 && base.at < t) { sw = 0; t = base.at; } // サービス終了時刻 for (let i1 = 0; i1 < base.s; i1++) { if (base.sb[i1] > 0 && base.st_e[i1] <= t) { sw = i1 + 1; t = base.st_e[i1]; // 窓口i1のサービス終了時刻 } } return sw; } /**********************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**********************************/ Q_base.prototype.End_o_s = function() { let sw = -2; base.p_time = base.end; // 現在時刻 base.at = -1.0; // 次の客の到着時刻 for (let i1 = 0; i1 < base.s; i1++) { if (base.sb[i1] > 0) { // サービス中の客はいるか? if (sw == -2) { sw = -1; base.end = base.st_e[i1]; // 窓口i1のサービス終了時刻 } else { if (base.st_e[i1] > base.end) base.end = base.st_e[i1]; // 窓口i1のサービス終了時刻 } } } return sw; } /****************/ /* 客の到着処理 */ /****************/ Q_base.prototype.Arrive = function() { /* 客数の増加と次の客の到着時刻の設定 */ base.nc += 1; // 到着客数カウンタ base.p_time = base.at; // 現在時刻 base.at = base.p_time + base.Next_at(); // 次の客の到着時刻 if (base.at >= base.end) base.at = -1.0; /* 系内客数の処理 */ base.c_sc_t += cus.length * (base.p_time - base.sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 base.sc_t = base.p_time; // 現在の系内客数になった時刻 if (cus.length+1 > base.m_sc) base.m_sc = cus.length + 1; // 最大系内客数 /* 窓口に空きがない場合 */ if (base.asb == 0) { let ct = new Customer(base.nc, -1, base.p_time); cus.push(ct); // 客の登録(系内客数) base.c_lq_t += que.length * (base.p_time - base.lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 que.push(base.nc); // 客の登録(待ち行列) base.lq_t = base.p_time; // 現在の待ち行列長になった時刻 if (que.length > base.m_lq) base.m_lq = que.length; // 最大待ち行列長 } /* すぐサービスを受けられる場合 */ else { let k = -1; for (let i1 = 0; i1 < base.s && k < 0; i1++) { if (base.sb[i1] == 0) { let ct = new Customer(base.nc, i1, base.p_time); cus.push(ct); // 客の登録(系内客数) k = i1; base.sb[k] = base.nc; // サービスを受けている客番号 base.st_e[k] = base.p_time + base.Next_sv(); // 窓口kのサービス終了時刻 base.asb -= 1; // 空いている窓口数 } } base.st_s[k] = base.p_time; // 窓口kがふさがった時刻 if (base.asb == 0) base.asb_t = base.p_time; // すべての窓口がふさがった時刻 } } /*********************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /*********************************/ Q_base.prototype.Service = function(k) { /* 時間の設定 */ k -= 1; base.p_time = base.st_e[k]; // 現在時刻 base.st_e[k] = -1.0; // サービス終了時間 /* 系内客数の処理 */ base.c_sc_t += cus.length * (base.p_time - base.sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 base.sc_t = base.p_time; // 現在の系内客数になった時刻 /* 滞在時間の処理 */ let n = base.Search(base.sb[k]); let x1 = base.p_time - cus[n].time; base.c_sys += x1; // 滞在時間の累計 if (x1 > base.m_sys) base.m_sys = x1; // 最大滞在時間 cus.splice(n, 1); // 客の削除(系内客数) /* 窓口使用時間の処理 */ base.asb += 1; // 空いている窓口数 base.sb[k] = 0; // 窓口kを空き状態にする base.c_sb[k] += (base.p_time - base.st_s[k]); // 窓口kがふさがっている時間の累計 /* 待ち行列がある場合 */ if (que.length > 0) { base.asb -= 1; // 開いている窓口数 base.c_lq_t += que.length * (base.p_time - base.lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 n = que.shift(); // 客の削除(待ち行列) base.lq_t = base.p_time; // 現在の待ち行列長になった時刻 let m = base.Search(n); x1 = base.p_time - cus[m].time; base.c_wt += x1; // 待ち時間の累計 if (x1 > base.m_wt) base.m_wt = x1; // 最大待ち時間 let k = -1; for (let i1 = 0; i1 < base.s && k < 0; i1++) { if (base.sb[i1] == 0) { k = i1; base.sb[k] = n; // 窓口kの客番号 base.st_e[k] = base.p_time + base.Next_sv(); // 窓口kのサービス終了時刻 base.st_s[k] = base.p_time; // 窓口kがふさがった時刻 cus[m].state = k; // 客の状態変更 } } } /* 待ち行列がない場合 */ else { if (base.asb == 1) base.c_asb += (base.p_time - base.asb_t); // すべての窓口がふさがっている時間の累計 } } /****************************/ /* 指定した客の配列上の位置 */ /* nm : 客番号 */ /* return : 要素番号 */ /****************************/ Q_base.prototype.Search = function(nm) { let n = -1; for (let i1 = 0; i1 < cus.length; i1++) { if (cus[i1].num == nm) { n = i1; break; } } return n; } /************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /************************/ Q_base.prototype.Output = function() { let ram = 1.0 / base.m_a; let myu = 1.0 / base.m_s; let rou = ram / (base.s * myu); let pi, p0; if (base.s == 1) { p0 = 1.0 - rou; pi = rou; } else { p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))); pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)); } let Lq = pi * rou / (1.0 - rou); let L = Lq + base.s * rou; let Wq = Lq / ram; let W = Wq + 1.0 / myu; let str = "シミュレーション時間=" + Math.round(base.p_time) + " 客数=" + base.nc + " ρ=" + Math.round(1000*rou)/1000 + " p0=" + Math.round(1000*p0)/1000 + "\n"; str += " すべての窓口が塞がっている割合=" + Math.round(1000*base.c_asb/base.p_time)/1000 + " (" + Math.round(1000*pi)/1000 + ")\n"; str += " 各窓口が塞がっている割合\n"; for (let i1 = 0; i1 < base.s; i1++) str += " " + (i1+1) + " " + Math.round(1000*base.c_sb[i1]/base.p_time)/1000 + "\n"; str += " 平均待ち行列長=" + Math.round(1000*base.c_lq_t/base.p_time)/1000 + " (" + Math.round(1000*Lq)/1000 + ") 最大待ち行列長=" + base.m_lq + "\n"; str += " 平均系内客数 =" + Math.round(1000*base.c_sc_t/base.p_time)/1000 + " (" + Math.round(1000*L)/1000 + ") 最大系内客数 =" + base.m_sc + "\n"; str += " 平均待ち時間 =" + Math.round(1000*base.c_wt/base.nc)/1000 + " (" + Math.round(1000*Wq)/1000 + ") 最大待ち時間 =" + Math.round(base.m_wt) + "\n"; str += " 平均滞在時間 =" + Math.round(1000*base.c_sys/base.nc)/1000 + " (" + Math.round(1000*W)/1000 + ") 最大滞在時間 =" + Math.round(base.m_sys) + "\n"; document.getElementById("res").value = str; }
<?php /******************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /******************************/ /************************/ /* クラスCustomerの定義 */ /************************/ class Customer { public $time; // 到着時刻 public $state; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 /*********************/ /* コンストラクタ */ /* s : 状態 */ /* t : 到着時刻 */ /*******************************/ function Customer($s, $t) { $this->time = $t; $this->state = $s; } } /**********************/ /* クラスQ_baseの定義 */ /**********************/ class Q_base { private $s; // 窓口の数 private $asb; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている private $sb; // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 private $asb_t; // すべての窓口がふさがった時刻 private $c_asb; // すべての窓口がふさがっている時間の累計 private $c_sb; // 各窓口がふさがっている時間の累計 private $st_e; // 各窓口のサービス終了時刻 private $st_s; // 各窓口がふさがった時刻 private $m_lq; // 最大待ち行列長 private $c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計 private $c_wt; // 待ち時間の累計 private $lq_t; // 現在の待ち行列長になった時刻 private $m_wt; // 最大待ち時間 private $c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計 private $c_sys; // 滞在時間の累計 private $m_sys; // 最大滞在時間 private $sc_t; // 現在の系内客数になった時刻 private $m_sc; // 最大系内客数 private $m_a; // 到着時間間隔の平均値 private $m_s; // サービス時間の平均値 private $at; // 次の客の到着時刻(負の時は,終了) private $p_time; // 現在時刻 private $end; // シミュレーション終了時刻 private $nc; // 到着客数カウンタ private $cus; // 系内にいる客のリスト private $que; // 待ち行列 /*****************************************/ /* コンストラクタ */ /* s_i : 窓口の数 */ /* m_a_i : 到着時間間隔の平均値 */ /* m_s_i : サービス時間の平均値 */ /* end_i : シミュレーション終了時刻 */ /*****************************************/ function Q_base ($s_i, $m_a_i, $m_s_i, $end_i) { /* 設定 */ $this->s = $s_i; $this->m_a = $m_a_i; $this->m_s = $m_s_i; $this->end = $end_i; /* 領域の確保 */ $this->sb = array(); $this->c_sb = array(); $this->st_e = array(); $this->st_s = array(); $this->cus = array(); $this->que = array(); for ($i1 = 0; $i1 < $this->s; $i1++) { $this->sb[$i1] = 0; $this->c_sb[$i1] = 0.0; } /* 初期設定 */ $this->p_time = 0.0; $this->nc = 0; $this->asb = $this->s; $this->m_lq = 0; $this->m_sc = 0; $this->c_asb = 0.0; $this->c_wt = 0.0; $this->m_wt = 0.0; $this->c_lq_t = 0.0; $this->lq_t = 0.0; $this->m_sys = 0.0; $this->c_sys = 0.0; $this->c_sc_t = 0.0; $this->sc_t = 0.0; /* 乱数の初期設定 */ mt_srand(); /* 最初の客の到着時刻の設定 */ $this->at = $this->p_time + $this->Next_at(); } /********************************/ /* 次の客の到着までの時間の発生 */ /********************************/ function Next_at() { return -$this->m_a * log(mt_rand() / mt_getrandmax()); } /************************/ /* サービス時間の発生 */ /************************/ function Next_sv() { return -$this->m_s * log(mt_rand() / mt_getrandmax()); } /**************/ /* 全体の制御 */ /**************/ function Control() { $sw = 0; while ($sw > -2) { $sw = $this->Next(); // 次の処理の選択 if ($sw == -1) $sw = $this->End_o_s(); // シミュレーションの終了 else { if ($sw == 0) $this->Arrive(); // 客の到着処理 else $this->Service($sw); // サービスの終了 } } } /**************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /**************************************************/ function Next() { $sw = -1; $t = $this->end; // シミュレーション終了時刻で初期設定 // 次の客の到着時刻 if ($this->at >= 0.0 && $this->at < $t) { $sw = 0; $t = $this->at; } // サービス終了時刻 for ($i1 = 0; $i1 < $this->s; $i1++) { if ($this->sb[$i1] > 0 && $this->st_e[$i1] <= $t) { $sw = $i1 + 1; $t = $this->st_e[$i1]; // 窓口i1のサービス終了時刻 } } return $sw; } /**********************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**********************************/ function End_o_s() { $sw = -2; $this->p_time = $this->end; // 現在時刻 $this->at = -1.0; // 次の客の到着時刻 for ($i1 = 0; $i1 < $this->s; $i1++) { if ($this->sb[$i1] > 0) { // サービス中の客はいるか? if ($sw == -2) { $sw = -1; $this->end = $this->st_e[$i1]; // 窓口i1のサービス終了時刻 } else { if ($this->st_e[$i1] > $this->end) $this->end = $this->st_e[$i1]; // 窓口i1のサービス終了時刻 } } } return $sw; } /****************/ /* 客の到着処理 */ /****************/ function Arrive() { /* 客数の増加と次の客の到着時刻の設定 */ $this->nc += 1; // 到着客数カウンタ $this->p_time = $this->at; // 現在時刻 $this->at = $this->p_time + $this->Next_at(); // 次の客の到着時刻 if ($this->at >= $this->end) $this->at = -1.0; /* 系内客数の処理 */ $this->c_sc_t += (count($this->cus) * ($this->p_time - $this->sc_t)); // 系内客数にその数が継続した時間を乗じた値の累計 $this->sc_t = $this->p_time; // 現在の系内客数になった時刻 if (count($this->cus)+1 > $this->m_sc) $this->m_sc = count($this->cus) + 1; // 最大系内客数 /* 窓口に空きがない場合 */ if ($this->asb == 0) { $ct_p = new Customer(-1, $this->p_time); $this->cus['no'.strval($this->nc)] = $ct_p; // 客の登録(系内客数) $this->c_lq_t += count($this->que) * ($this->p_time - $this->lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 array_push($this->que, $this->nc); // 客の登録(待ち行列) $this->lq_t = $this->p_time; // 現在の待ち行列長になった時刻 if (count($this->que) > $this->m_lq) $this->m_lq = count($this->que); // 最大待ち行列長 } /* すぐサービスを受けられる場合 */ else { $k = -1; for ($i1 = 0; $i1 < $this->s && $k < 0; $i1++) { if ($this->sb[$i1] == 0) { $ct_p = new Customer($i1, $this->p_time); $this->cus['no'.strval($this->nc)] = $ct_p; // 客の登録(系内客数) $k = $i1; $this->sb[$k] = $this->nc; // サービスを受けている客番号 $this->st_e[$k] = $this->p_time + $this->Next_sv(); // 窓口kのサービス終了時刻 $this->asb -= 1; // 空いている窓口数 } } $this->st_s[$k] = $this->p_time; // 窓口kがふさがった時刻 if ($this->asb == 0) $this->asb_t = $this->p_time; // すべての窓口がふさがった時刻 } } /*********************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /*********************************/ function Service($k) { /* 時間の設定 */ $k -= 1; $this->p_time = $this->st_e[$k]; // 現在時刻 $this->st_e[$k] = -1.0; // サービス終了時間 /* 系内客数の処理 */ $this->c_sc_t += (count($this->cus) * ($this->p_time - $this->sc_t)); // 系内客数にその数が継続した時間を乗じた値の累計 $this->sc_t = $this->p_time; // 現在の系内客数になった時刻 /* 滞在時間の処理 */ $it = $this->cus['no'.strval($this->sb[$k])]; $x1 = $this->p_time - $it->time; $this->c_sys += $x1; // 滞在時間の累計 if ($x1 > $this->m_sys) $this->m_sys = $x1; // 最大滞在時間 unset($this->cus['no'.strval($this->sb[$k])]); // 客の削除(系内客数) /* 窓口使用時間の処理 */ $this->asb += 1; // 空いている窓口数 $this->sb[$k] = 0; // 窓口kを空き状態にする $this->c_sb[$k] += ($this->p_time - $this->st_s[$k]); // 窓口kがふさがっている時間の累計 /* 待ち行列がある場合 */ if (count($this->que) > 0) { $this->asb -= 1; // 開いている窓口数 $this->c_lq_t += count($this->que) * ($this->p_time - $this->lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 $n = array_shift($this->que); // 客の削除(待ち行列) $this->lq_t = $this->p_time; // 現在の待ち行列長になった時刻 $it = $this->cus['no'.strval($n)]; $x1 = $this->p_time - $it->time; $this->c_wt += $x1; // 待ち時間の累計 if ($x1 > $this->m_wt) $this->m_wt = $x1; // 最大待ち時間 $k = -1; for ($i1 = 0; $i1 < $this->s && $k < 0; $i1++) { if ($this->sb[$i1] == 0) { $k = $i1; $this->sb[$k] = $n; // 窓口kの客番号 $this->st_e[$k] = $this->p_time + $this->Next_sv(); // 窓口kのサービス終了時刻 $this->st_s[$k] = $this->p_time; // 窓口kがふさがった時刻 $it->state = $k; // 客の状態変更 } } } /* 待ち行列がない場合 */ else { if ($this->asb == 1) $this->c_asb += ($this->p_time - $this->asb_t); // すべての窓口がふさがっている時間の累計 } } /************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /************************/ function Output() { $rn = floatval($this->nc); $rs = floatval($this->s); $ram = 1.0 / $this->m_a; $myu = 1.0 / $this->m_s; $rou = $ram / ($rs * $myu); if ($this->s == 1) { $p0 = 1.0 - $rou; $pi = $rou; } else { $p0 = 1.0 / (1.0 + 2.0 * $rou + 4.0 * $rou * $rou / (2.0 * (1.0 - $rou))); $pi = 4.0 * $rou * $rou * $p0 / (2.0 * (1.0 - $rou)); } $Lq = $pi * $rou / (1.0 - $rou); $L = $Lq + $rs * $rou; $Wq = $Lq / $ram; $W = $Wq + 1.0 / $myu; printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n", $this->p_time, $this->nc, $rou, $p0); printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n", $this->c_asb/$this->p_time, $pi); printf(" 各窓口が塞がっている割合\n"); for ($i1 = 0; $i1 < $this->s; $i1++) printf(" %d %.3f\n", $i1+1, $this->c_sb[$i1]/$this->p_time); printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n", $this->c_lq_t/$this->p_time, $Lq, $this->m_lq); printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n", $this->c_sc_t/$this->p_time, $L, $this->m_sc); printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n", $this->c_wt/$rn, $Wq, $this->m_wt); printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n", $this->c_sys/$rn, $W, $this->m_sys); } } /****************/ /* main program */ /****************/ /* 入力データ */ printf("窓口の数は? "); fscanf(STDIN, "%d", $s); printf("シミュレーション終了時間? "); fscanf(STDIN, "%lf", $end); printf(" 到着時間間隔の平均値は? "); fscanf(STDIN, "%lf", $m_a); printf(" サービス時間の平均値は? "); fscanf(STDIN, "%lf", $m_s); /* システムの定義 */ $base = new Q_base($s, $m_a, $m_s, $end); /* シミュレーションの実行 */ $base->Control(); /* 出力 */ $base->Output(); ?>
############################# # 簡単な待ち行列問題(M/M/s) # coded by Y.Suganuma ############################# ######################## # クラスCustomerの定義 ######################## class Customer ##################### # コンストラクタ # s : 状態 # t : 到着時刻 ##################### def initialize(s, t) @_state = s # 客の状態 # =-1 : 待ち行列に入っている # >=0 : サービスを受けている窓口番号 @_time = t # 到着時刻 end attr_accessor("_state", "_time") end ######################## # クラスQ_baseの定義 ######################## class Q_base ######################################### # コンストラクタ # s_i : 窓口の数 # m_a_i : 到着時間間隔の平均値 # m_s_i : サービス時間の平均値 # stp_i : シミュレーション終了時刻 ######################################### def initialize(s_i, m_a_i, m_s_i, stp_i) # 設定 @_s = s_i # 窓口の数 @_m_a = m_a_i # 到着時間間隔の平均値 @_m_s = m_s_i # サービス時間の平均値 @_stp = stp_i # シミュレーション終了時刻 # 領域の確保 @_sb = Array.new(@_s) # 各窓口の空き状況 # =0 : 窓口は空いている # >0 : サービスを受けている客番号 @_c_sb = Array.new(@_s) # 各窓口がふさがっている時間の累計 for i1 in 0 ... @_s @_sb[i1] = 0 @_c_sb[i1] = 0.0 end @_st_e = Array.new(@_s) # 各窓口のサービス終了時刻 @_st_s = Array.new(@_s) # 各窓口がふさがった時刻 # 初期設定 @_p_time = 0.0 # 現在時刻 @_nc = 0 # 到着客数カウンタ @_asb = @_s # 全窓口の空き状況 # =0 : すべての窓口がふさがっている # =n : n個の窓口が空いている @_m_lq = 0 # 最大待ち行列長 @_m_sc = 0 # 最大系内客数 @_c_asb = 0.0 # すべての窓口がふさがっている時間の累計 @_c_wt = 0.0 # 待ち時間の累計 @_m_wt = 0.0 # 最大待ち時間 @_c_lq_t = 0.0 # 待ち行列長にその長さが継続した時間を乗じた値の累計 @_lq_t = 0.0 # 現在の待ち行列長になった時刻 @_m_sys = 0.0 # 最大滞在時間 @_c_sys = 0.0 # 滞在時間の累計 @_c_sc_t = 0.0 # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = 0.0 # 現在の系内客数になった時刻 @_asb_t = 0.0 # すべての窓口がふさがった時刻 @_cus = Hash.new() # 系内にいる客のリスト @_que = Array.new() # 待ち行列 # 最初の客の到着時刻の設定 @_at = @_p_time + Next_at() # 次の客の到着時刻(負の時は,終了) end ################################ # 次の客の到着までの時間の発生 ################################ def Next_at() return -@_m_a * Math.log(rand(0)) end ##################### # サービス時間の発生 ##################### def Next_sv() return -@_m_s * Math.log(rand(0)) end ############## # 全体の制御 ############## def Control() sw = 0 while sw > -2 sw = Next() # 次の処理の選択 if sw == -1 sw = End_o_s() # シミュレーションの終了 else if sw == 0 Arrive() # 客の到着処理 else Service(sw) # サービスの終了 end end end end ################################################## # 次の処理の決定 # return : =-1 : シミュレーションの終了 # =0 : 客の到着処理 # =i : i番目の窓口のサービス終了 ################################################## def Next() sw = -1 t = @_stp # シミュレーション終了時刻で初期設定 # 次の客の到着時刻 if @_at >= 0.0 && @_at < t sw = 0 t = @_at end # サービス終了時刻 for i1 in 0 ... @_s if @_sb[i1] > 0 && @_st_e[i1] <= t sw = i1 + 1 t = @_st_e[i1] # 窓口i1のサービス終了時刻 end end return sw end ################################## # 終了処理 # return : =-1 : 終了前処理 # =-2 : 実際の終了 ################################## def End_o_s() sw = -2 @_p_time = @_stp # 現在時刻 @_at = -1.0 # 次の客の到着時刻 for i1 in 0 ... @_s if @_sb[i1] > 0 # サービス中の客はいるか? if sw == -2 sw = -1 @_stp = @_st_e[i1] # 窓口i1のサービス終了時刻 else if @_st_e[i1] > @_stp @_stp = @_st_e[i1] # 窓口i1のサービス終了時刻 end end end end return sw end ################ # 客の到着処理 ################ def Arrive() # 客数の増加と次の客の到着時刻の設定 @_nc += 1 # 到着客数カウンタ @_p_time = @_at # 現在時刻 @_at = @_p_time + Next_at() # 次の客の到着時刻 if @_at >= @_stp @_at = -1.0 end # 系内客数の処理 @_c_sc_t += @_cus.length * (@_p_time - @_sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = @_p_time # 現在の系内客数になった時刻 if @_cus.length+1 > @_m_sc @_m_sc = @_cus.length + 1 # 最大系内客数 end # 窓口に空きがない場合 if @_asb == 0 ct_p = Customer.new(-1, @_p_time) @_cus[@_nc] = ct_p # 客の登録(系内客数) @_c_lq_t += @_que.length * (@_p_time - @_lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 @_que.push(@_nc) # 客の登録(待ち行列) @_lq_t = @_p_time # 現在の待ち行列長になった時刻 if @_que.length > @_m_lq @_m_lq = @_que.length # 最大待ち行列長 end # すぐサービスを受けられる場合 else k = -1 for i1 in 0 ... @_s if @_sb[i1] == 0 ct_p = Customer.new(i1, @_p_time) @_cus[@_nc] = ct_p # 客の登録(系内客数) k = i1 @_sb[k] = @_nc # サービスを受けている客番号 @_st_e[k] = @_p_time + Next_sv() # 窓口kのサービス終了時刻 @_asb -= 1 # 空いている窓口数 break end end @_st_s[k] = @_p_time # 窓口kがふさがった時刻 if @_asb == 0 @_asb_t = @_p_time # すべての窓口がふさがった時刻 end end end ################################# # サービス終了時の処理 # k : サービス終了窓口番号 ################################# def Service(k) # 時間の設定 k -= 1 @_p_time = @_st_e[k] # 現在時刻 @_st_e[k] = -1.0 # サービス終了時間 # 系内客数の処理 @_c_sc_t += @_cus.length * (@_p_time - @_sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = @_p_time # 現在の系内客数になった時刻 # 滞在時間の処理 x1 = @_p_time - @_cus[@_sb[k]]._time @_c_sys += x1 # 滞在時間の累計 if x1 > @_m_sys @_m_sys = x1 # 最大滞在時間 end @_cus.delete(@_sb[k]) # 客の削除(系内客数) # 窓口使用時間の処理 @_asb += 1 # 空いている窓口数 @_sb[k] = 0 # 窓口kを空き状態にする @_c_sb[k] += (@_p_time - @_st_s[k]) # 窓口kがふさがっている時間の累計 # 待ち行列がある場合 if @_que.length > 0 @_asb -= 1 # 開いている窓口数 @_c_lq_t += @_que.length * (@_p_time - @_lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 n = @_que.delete_at(0) @_lq_t = @_p_time # 現在の待ち行列長になった時刻 x1 = @_p_time - @_cus[n]._time @_c_wt += x1 # 待ち時間の累計 if x1 > @_m_wt @_m_wt = x1 # 最大待ち時間 end k = -1 for i1 in 0 ... @_s if @_sb[i1] == 0 k = i1 @_sb[k] = n # 窓口kの客番号 @_st_e[k] = @_p_time + Next_sv() # 窓口kのサービス終了時刻 @_st_s[k] = @_p_time # 窓口kがふさがった時刻 @_cus[n]._state = k # 客の状態変更 break end end # 待ち行列がない場合 else if @_asb == 1 @_c_asb += (@_p_time - @_asb_t) # すべての窓口がふさがっている時間の累計 end end end ######################## # 結果の出力 # (カッコ内は理論値) ######################## def Output() rn = Float(@_nc) rs = Float(@_s) ram = 1.0 / @_m_a myu = 1.0 / @_m_s rou = ram / (rs * myu) if @_s == 1 p0 = 1.0 - rou pi = rou else p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))) pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)) end lq = pi * rou / (1.0 - rou) l = lq + rs * rou wq = lq / ram w = wq + 1.0 / myu printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n", @_p_time, @_nc, rou, p0) printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n", @_c_asb/@_p_time, pi) printf(" 各窓口が塞がっている割合\n") for i1 in 0 ... @_s printf(" %d %.3f\n", (i1+1), @_c_sb[i1]/@_p_time) end printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n", @_c_lq_t/@_p_time, lq, @_m_lq) printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n", @_c_sc_t/@_p_time, l, @_m_sc) printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n", @_c_wt/rn, wq, @_m_wt) printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n", @_c_sys/rn, w, @_m_sys) end end # 入力データ print("窓口の数は? ") s = Integer(gets()) print("シミュレーション終了時間? ") stp = Float(gets()) print(" 到着時間間隔の平均値は? ") m_a = Float(gets()) print(" サービス時間の平均値は? ") m_s = Float(gets()) # システムの定義 base = Q_base.new(s, m_a, m_s, stp) # シミュレーションの実行 srand() base.Control() # 出力 base.Output()
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * ######################## # クラスCustomerの定義 ######################## class Customer : ##################### # コンストラクタ # s : 状態 # t : 到着時刻 ##################### def __init__(self, s, t) : self.state = s # 客の状態 # =-1 : 待ち行列に入っている # >=0 : サービスを受けている窓口番号 self.time = t # 到着時刻 ######################## # クラスQ_baseの定義 ######################## class Q_base : ######################################### # コンストラクタ # s_i : 窓口の数 # m_a_i : 到着時間間隔の平均値 # m_s_i : サービス時間の平均値 # end_i : シミュレーション終了時刻 ######################################### def __init__(self, s_i, m_a_i, m_s_i, end_i) : # 設定 self.s = s_i # 窓口の数 self.m_a = m_a_i # 到着時間間隔の平均値 self.m_s = m_s_i # サービス時間の平均値 self.end = end_i # シミュレーション終了時刻 # 領域の確保 self.sb = np.zeros(self.s, np.int) # 各窓口の空き状況 # =0 : 窓口は空いている # >0 : サービスを受けている客番号 self.c_sb = np.zeros(self.s, np.float) # 各窓口がふさがっている時間の累計 self.st_e = np.empty(self.s, np.float) # 各窓口のサービス終了時刻 self.st_s = np.empty(self.s, np.float) # 各窓口がふさがった時刻 # 初期設定 self.p_time = 0.0 # 現在時刻 self.nc = 0 # 到着客数カウンタ self.asb = self.s # 全窓口の空き状況 # =0 : すべての窓口がふさがっている # =n : n個の窓口が空いている self.m_lq = 0 # 最大待ち行列長 self.m_sc = 0 # 最大系内客数 self.c_asb = 0.0 # すべての窓口がふさがっている時間の累計 self.c_wt = 0.0 # 待ち時間の累計 self.m_wt = 0.0 # 最大待ち時間 self.c_lq_t = 0.0 # 待ち行列長にその長さが継続した時間を乗じた値の累計 self.lq_t = 0.0 # 現在の待ち行列長になった時刻 self.m_sys = 0.0 # 最大滞在時間 self.c_sys = 0.0 # 滞在時間の累計 self.c_sc_t = 0.0 # 系内客数にその数が継続した時間を乗じた値の累計 self.sc_t = 0.0 # 現在の系内客数になった時刻 self.asb_t = 0.0 # すべての窓口がふさがった時刻 self.cus = dict() # 系内にいる客のリスト self.que = [] # 待ち行列 # 最初の客の到着時刻の設定 self.at = self.p_time + self.Next_at() # 次の客の到着時刻(負の時は,終了) ################################ # 次の客の到着までの時間の発生 ################################ def Next_at(self) : # return -self.m_a * log(random()) return expovariate(1.0 / self.m_a) ##################### # サービス時間の発生 ##################### def Next_sv(self) : # return -self.m_s * log(random())-4.0 * log(random()) return expovariate(1.0 / self.m_s) ############## # 全体の制御 ############## def Control(self) : sw = 0 while sw > -2 : sw = self.Next() # 次の処理の選択 if sw == -1 : sw = self.End_o_s() # シミュレーションの終了 else : if sw == 0 : self.Arrive() # 客の到着処理 else : self.Service(sw) # サービスの終了 ################################################## # 次の処理の決定 # return : =-1 : シミュレーションの終了 # =0 : 客の到着処理 # =i : i番目の窓口のサービス終了 ################################################## def Next(self) : sw = -1 t = self.end # シミュレーション終了時刻で初期設定 # 次の客の到着時刻 if self.at >= 0.0 and self.at < t : sw = 0 t = self.at # サービス終了時刻 for i1 in range(0, self.s) : if self.sb[i1] > 0 and self.st_e[i1] <= t : sw = i1 + 1 t = self.st_e[i1] # 窓口i1のサービス終了時刻 return sw ################################## # 終了処理 # return : =-1 : 終了前処理 # =-2 : 実際の終了 ################################## def End_o_s(self) : sw = -2 self.p_time = self.end # 現在時刻 self.at = -1.0 # 次の客の到着時刻 for i1 in range(0, self.s) : if self.sb[i1] > 0 : # サービス中の客はいるか? if sw == -2 : sw = -1 self.end = self.st_e[i1] # 窓口i1のサービス終了時刻 else : if self.st_e[i1] > self.end : self.end = self.st_e[i1] # 窓口i1のサービス終了時刻 return sw ################ # 客の到着処理 ################ def Arrive(self) : # 客数の増加と次の客の到着時刻の設定 self.nc += 1 # 到着客数カウンタ self.p_time = self.at # 現在時刻 self.at = self.p_time + self.Next_at() # 次の客の到着時刻 if self.at >= self.end : self.at = -1.0 # 系内客数の処理 self.c_sc_t += len(self.cus) * (self.p_time - self.sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 self.sc_t = self.p_time # 現在の系内客数になった時刻 if len(self.cus)+1 > self.m_sc : self.m_sc = len(self.cus) + 1 # 最大系内客数 # 窓口に空きがない場合 if self.asb == 0 : ct_p = Customer(-1, self.p_time) self.cus[self.nc] = ct_p # 客の登録(系内客数) self.c_lq_t += len(self.que) * (self.p_time - self.lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 self.que.append(self.nc) # 客の登録(待ち行列) self.lq_t = self.p_time # 現在の待ち行列長になった時刻 if len(self.que) > self.m_lq : self.m_lq = len(self.que) # 最大待ち行列長 # すぐサービスを受けられる場合 else : k = -1 for i1 in range(0, self.s) : if self.sb[i1] == 0 : ct_p = Customer(i1, self.p_time) self.cus[self.nc] = ct_p # 客の登録(系内客数) k = i1 self.sb[k] = self.nc # サービスを受けている客番号 self.st_e[k] = self.p_time + self.Next_sv() # 窓口kのサービス終了時刻 self.asb -= 1 # 空いている窓口数 break self.st_s[k] = self.p_time # 窓口kがふさがった時刻 if self.asb == 0 : self.asb_t = self.p_time # すべての窓口がふさがった時刻 ################################# # サービス終了時の処理 # k : サービス終了窓口番号 ################################# def Service(self, k) : # 時間の設定 k -= 1 self.p_time = self.st_e[k] # 現在時刻 self.st_e[k] = -1.0 # サービス終了時間 # 系内客数の処理 self.c_sc_t += len(self.cus) * (self.p_time - self.sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 self.sc_t = self.p_time # 現在の系内客数になった時刻 # 滞在時間の処理 x1 = self.p_time - self.cus[self.sb[k]].time self.c_sys += x1 # 滞在時間の累計 if x1 > self.m_sys : self.m_sys = x1 # 最大滞在時間 self.cus.pop(self.sb[k]) # 客の削除(系内客数) # 窓口使用時間の処理 self.asb += 1 # 空いている窓口数 self.sb[k] = 0 # 窓口kを空き状態にする self.c_sb[k] += (self.p_time - self.st_s[k]) # 窓口kがふさがっている時間の累計 # 待ち行列がある場合 if len(self.que) > 0 : self.asb -= 1 # 開いている窓口数 self.c_lq_t += len(self.que) * (self.p_time - self.lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 n = self.que.pop(0) self.lq_t = self.p_time # 現在の待ち行列長になった時刻 x1 = self.p_time - self.cus[n].time self.c_wt += x1 # 待ち時間の累計 if x1 > self.m_wt : self.m_wt = x1 # 最大待ち時間 k = -1 for i1 in range(0, self.s) : if self.sb[i1] == 0 : k = i1 self.sb[k] = n # 窓口kの客番号 self.st_e[k] = self.p_time + self.Next_sv() # 窓口kのサービス終了時刻 self.st_s[k] = self.p_time # 窓口kがふさがった時刻 self.cus[n].state = k # 客の状態変更 break # 待ち行列がない場合 else : if self.asb == 1 : self.c_asb += (self.p_time - self.asb_t) # すべての窓口がふさがっている時間の累計 ######################## # 結果の出力 # (カッコ内は理論値) ######################## def Output(self) : rn = float(self.nc) rs = float(self.s) ram = 1.0 / self.m_a myu = 1.0 / self.m_s rou = ram / (rs * myu) if self.s == 1 : p0 = 1.0 - rou pi = rou else : p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))) pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)) Lq = pi * rou / (1.0 - rou) L = Lq + rs * rou Wq = Lq / ram W = Wq + 1.0 / myu print("シミュレーション終了時間={0:.3f} 客数={1:d} ρ={2:.3f} p0={3:.3f}".format(self.p_time, self.nc, rou, p0)) print(" すべての窓口が塞がっている割合={0:.3f} ({1:.3f})".format(self.c_asb/self.p_time, pi)) print(" 各窓口が塞がっている割合") for i1 in range(0, self.s) : print(" {0:d} {1:.3f}".format(i1+1, self.c_sb[i1]/self.p_time)) print(" 平均待ち行列長={0:.3f} ({1:.3f}) 最大待ち行列長={2:d}".format(self.c_lq_t/self.p_time, Lq, self.m_lq)) print(" 平均系内客数 ={0:.3f} ({1:.3f}) 最大系内客数 ={2:d}".format(self.c_sc_t/self.p_time, L, self.m_sc)) print(" 平均待ち時間 ={0:.3f} ({1:.3f}) 最大待ち時間 ={2:.3f}".format(self.c_wt/rn, Wq, self.m_wt)) print(" 平均滞在時間 ={0:.3f} ({1:.3f}) 最大滞在時間 ={2:.3f}".format(self.c_sys/rn, W, self.m_sys)) ############################# # 簡単な待ち行列問題(M/M/s) # coded by Y.Suganuma ############################# # 入力データ s = int(input("窓口の数は? ")) end = float(input("シミュレーション終了時間? ")) m_a = float(input(" 到着時間間隔の平均値は? ")) m_s = float(input(" サービス時間の平均値は? ")) # システムの定義 base = Q_base(s, m_a, m_s, end) # シミュレーションの実行 seed() base.Control() # 出力 base.Output()
/******************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /******************************/ using System; using System.Collections.Generic; class Program { /****************/ /* main program */ /****************/ static void Main() { /* 入力データ */ Console.Write("窓口の数は? "); int s = int.Parse(Console.ReadLine()); Console.Write("シミュレーション終了時間? "); double end = double.Parse(Console.ReadLine()); Console.Write(" 到着時間間隔の平均値は? "); double m_a = double.Parse(Console.ReadLine()); Console.Write(" サービス時間の平均値は? "); double m_s = double.Parse(Console.ReadLine()); /* システムの定義 */ Q_base base1 = new Q_base(s, m_a, m_s, end); /* シミュレーションの実行 */ base1.Control(); /* 出力 */ base1.Output(); } } /**********************/ /* クラスQ_baseの定義 */ /**********************/ class Q_base { int s; // 窓口の数 int asb; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている int [] sb; // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 double asb_t; // すべての窓口がふさがった時間 double c_asb; // すべての窓口がふさがっている時間の累計 double [] c_sb; // 各窓口がふさがっている時間の累計 double [] st_e; // 各窓口のサービス終了時間 double [] st_s; // 各窓口がふさがった時間 int m_lq; // 最大待ち行列長 double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計 double c_wt; // 待ち時間の累計 double lq_t; // 現在の待ち行列長になった時間 double m_wt; // 最大待ち時間 double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計 double c_sys; // 滞在時間の累計 double m_sys; // 最大滞在時間 double sc_t; // 現在の系内客数になった時間 int m_sc; // 最大系内客数 double m_a; // 到着時間間隔の平均値 double m_s; // サービス時間の平均値 double at; // 次の客の到着時間(負の時は,終了) double p_time; // 現在時間 double end; // シミュレーション終了時間 int nc; // 到着客数カウンタ Random rn; // 乱数 Dictionary<int, Customer> cus; // 系内にいる客のリスト Queue<int> que; // 待ち行列 /*****************************************/ /* コンストラクタ */ /* s_i : 窓口の数 */ /* m_a_i : 到着時間間隔の平均値 */ /* m_s_i : サービス時間の平均値 */ /* end_i : シミュレーション終了時間 */ /*****************************************/ public Q_base (int s_i, double m_a_i, double m_s_i, double end_i) { /* 設定 */ s = s_i; m_a = m_a_i; m_s = m_s_i; end = end_i; /* 領域の確保 */ sb = new int [s]; c_sb = new double [s]; st_e = new double [s]; st_s = new double [s]; for (int i1 = 0; i1 < s; i1++) { sb[i1] = 0; c_sb[i1] = 0.0; } cus = new Dictionary <int, Customer> (); que = new Queue <int> (); /* 初期設定 */ p_time = 0.0; nc = 0; asb = s; m_lq = 0; m_sc = 0; c_asb = 0.0; c_wt = 0.0; m_wt = 0.0; c_lq_t = 0.0; lq_t = 0.0; m_sys = 0.0; c_sys = 0.0; c_sc_t = 0.0; sc_t = 0.0; /* 乱数の初期設定 */ rn = new Random(); /* 最初の客の到着時間の設定 */ at = p_time + Next_at(); } /**********************************/ /* 次の客の到着までの時間の発生 */ /**********************************/ double Next_at() { return -m_a * Math.Log(rn.NextDouble()); } /************************/ /* サービス時間の発生 */ /************************/ double Next_sv() { return -m_s * Math.Log(rn.NextDouble()); } /**************/ /* 全体の制御 */ /**************/ public void Control() { int sw = 0; while (sw > -2) { sw = Next(); // 次の処理の選択 if (sw == -1) sw = End_o_s(); // シミュレーションの終了 else { if (sw == 0) Arrive(); // 客の到着処理 else Service(sw); // サービスの終了 } } } /**************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /**************************************************/ int Next() { int sw = -1; double t = end; // シミュレーション終了時刻で初期設定 // 次の客の到着時刻 if (at >= 0.0 && at < t) { sw = 0; t = at; } // サービス終了時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0 && st_e[i1] <= t) { sw = i1 + 1; t = st_e[i1]; // 窓口i1のサービス終了時刻 } } return sw; } /**********************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**********************************/ int End_o_s() { int sw = -2; p_time = end; // 現在時刻 at = -1.0; // 次の客の到着時刻 for (int i1 = 0; i1 < s; i1++) { if (sb[i1] > 0) { // サービス中の客はいるか? if (sw == -2) { sw = -1; end = st_e[i1]; // 窓口i1のサービス終了時刻 } else { if (st_e[i1] > end) end = st_e[i1]; // 窓口i1のサービス終了時刻 } } } return sw; } /****************************/ /* 客の到着処理 */ /* ct : 客リストの先頭 */ /****************************/ void Arrive() { /* 客数の増加と次の客の到着時刻の設定 */ nc += 1; // 到着客数カウンタ p_time = at; // 現在時刻 at = p_time + Next_at(); // 次の客の到着時刻 if (at >= end) at = -1.0; /* 系内客数の処理 */ c_sc_t += cus.Count * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 if (cus.Count+1 > m_sc) m_sc = cus.Count + 1; // 最大系内客数 /* 窓口に空きがない場合 */ if (asb == 0) { Customer ct_p = new Customer(-1, p_time); cus.Add(nc, ct_p); // 客の登録(系内客数) c_lq_t += que.Count * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 que.Enqueue(nc); // 客の登録(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 if (que.Count > m_lq) m_lq = que.Count; // 最大待ち行列長 } /* すぐサービスを受けられる場合 */ else { int k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { Customer ct_p = new Customer(i1, p_time); cus.Add(nc, ct_p); // 客の登録(系内客数) k = i1; sb[k] = nc; // サービスを受けている客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 asb -= 1; // 空いている窓口数 } } st_s[k] = p_time; // 窓口kがふさがった時刻 if (asb == 0) asb_t = p_time; // すべての窓口がふさがった時刻 } } /*********************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /* ct : 客リストの先頭 */ /*********************************/ void Service(int k) { /* 時間の設定 */ k -= 1; p_time = st_e[k]; // 現在時刻 st_e[k] = -1.0; // サービス終了時間 /* 系内客数の処理 */ c_sc_t += cus.Count * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time; // 現在の系内客数になった時刻 /* 滞在時間の処理 */ Customer ct = cus[sb[k]]; double x1 = p_time - ct.time; c_sys += x1; // 滞在時間の累計 if (x1 > m_sys) m_sys = x1; // 最大滞在時間 cus.Remove(sb[k]); // 客の削除(系内客数) /* 窓口使用時間の処理 */ asb += 1; // 空いている窓口数 sb[k] = 0; // 窓口kを空き状態にする c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計 /* 待ち行列がある場合 */ if (que.Count > 0) { asb -= 1; // 開いている窓口数 c_lq_t += que.Count * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計 int n = que.Dequeue(); // 客の削除(待ち行列) lq_t = p_time; // 現在の待ち行列長になった時刻 ct = cus[n]; x1 = p_time - ct.time; c_wt += x1; // 待ち時間の累計 if (x1 > m_wt) m_wt = x1; // 最大待ち時間 k = -1; for (int i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { k = i1; sb[k] = n; // 窓口kの客番号 st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻 st_s[k] = p_time; // 窓口kがふさがった時刻 ct.state = k; // 客の状態変更 } } } /* 待ち行列がない場合 */ else { if (asb == 1) c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計 } } /************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /************************/ public void Output() { double rn = (double)nc; double rs = (double)s; double ram = 1.0 / m_a; double myu = 1.0 / m_s; double rou = ram / (rs * myu); double p0, pi; if (s == 1) { p0 = 1.0 - rou; pi = rou; } else { p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))); pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)); } double Lq = pi * rou / (1.0 - rou); double L = Lq + rs * rou; double Wq = Lq / ram; double W = Wq + 1.0 / myu; Console.WriteLine("シミュレーション終了時間=" + p_time + " 客数=" + nc + " ρ=" + rou + " p0=" + p0); Console.WriteLine(" すべての窓口が塞がっている割合=" + (c_asb/p_time) + " (" + pi + ")"); Console.WriteLine(" 各窓口が塞がっている割合"); for (int i1 = 0; i1 < s; i1++) Console.WriteLine(" " + (i1+1) + " " + (c_sb[i1]/p_time)); Console.WriteLine(" 平均待ち行列長=" + (c_lq_t/p_time) + " (" + Lq + ") 最大待ち行列長=" + m_lq); Console.WriteLine(" 平均系内客数 =" + (c_sc_t/p_time) + " (" + L + ") 最大系内客数 =" + m_sc); Console.WriteLine(" 平均待ち時間 =" + (c_wt/rn) + " (" + Wq + ") 最大待ち時間 =" + m_wt); Console.WriteLine(" 平均滞在時間 =" + (c_sys/rn) + " (" + W + ") 最大滞在時間 =" + m_sys); } } /************************/ /* クラスCustomerの定義 */ /************************/ class Customer { public double time; // 到着時刻 public int state; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 /*******************/ /* コンストラクタ */ /* n : 客番号 */ /* s : 状態 */ /*******************/ public Customer (int s, double t) { time = t; state = s; } }
'****************************' ' 簡単な待ち行列問題(M/M/s)' ' coded by Y.Suganuma ' '****************************' Imports System.Collections.Generic Module Test Sub Main() ' ' 入力データ ' Console.Write("窓口の数は? ") Dim s As Integer = Integer.Parse(Console.ReadLine()) Console.Write("シミュレーション終了時間? ") Dim end_s As Double = Double.Parse(Console.ReadLine()) Console.Write(" 到着時間間隔の平均値は? ") Dim m_a As Double = Double.Parse(Console.ReadLine()) Console.Write(" サービス時間の平均値は? ") Dim m_s As Double = Double.Parse(Console.ReadLine()) ' ' システムの定義 ' Dim base1 As Q_base = new Q_base(s, m_a, m_s, end_s) ' ' シミュレーションの実行 ' base1.Control() ' ' 出力 ' base1.Output() End Sub '********************' ' クラスQ_baseの定義 ' '********************' Class Q_base Private s As Integer ' 窓口の数 Private asb As Integer ' 全窓口の空き状況 ' =0 : すべての窓口がふさがっている ' =n : n個の窓口が空いている Private sb() As Integer ' 各窓口の空き状況 ' =0 : 窓口は空いている ' >0 : サービスを受けている客番号 Private asb_t As Double ' すべての窓口がふさがった時間 Private c_asb As Double ' すべての窓口がふさがっている時間の累計 Private c_sb() As Double ' 各窓口がふさがっている時間の累計 Private st_e() As Double ' 各窓口のサービス終了時間 Private st_s() As Double ' 各窓口がふさがった時間 Private m_lq As Integer ' 最大待ち行列長 Private c_lq_t As Double ' 待ち行列長にその長さが継続した時間を乗じた値の累計 Private c_wt As Double ' 待ち時間の累計 Private lq_t As Double ' 現在の待ち行列長になった時間 Private m_wt As Double ' 最大待ち時間 Private c_sc_t As Double ' 系内客数にその数が継続した時間を乗じた値の累計 Private c_sys As Double ' 滞在時間の累計 Private m_sys As Double ' 最大滞在時間 Private sc_t As Double ' 現在の系内客数になった時間 Private m_sc As Integer ' 最大系内客数 Private m_a As Double ' 到着時間間隔の平均値 Private m_s As Double ' サービス時間の平均値 Private at As Double ' 次の客の到着時間(負の時は,終了) Private p_time As Double ' 現在時間 Private end_s As Double ' シミュレーション終了時間 Private nc As Integer ' 到着客数カウンタ Private rn As Random ' 乱数 Private cus As New Dictionary(Of Integer, Customer) ' 系内にいる客のリスト Private que As New Queue(Of Integer) ' 待ち行列 '***************************************' ' コンストラクタ ' ' s_i : 窓口の数 ' ' m_a_i : 到着時間間隔の平均値 ' ' m_s_i : サービス時間の平均値 ' ' end_i : シミュレーション終了時間 ' '***************************************' Public Sub New(s_i As Integer, m_a_i As Double, m_s_i As Double, end_i As Double) ' ' 設定 ' s = s_i m_a = m_a_i m_s = m_s_i end_s = end_i ' ' 領域の確保 ' ReDim sb(s) ReDim c_sb(s) ReDim st_e(s) ReDim st_s(s) For i1 As Integer = 0 To s-1 sb(i1) = 0 c_sb(i1) = 0.0 Next ' ' 初期設定 ' p_time = 0.0 nc = 0 asb = s m_lq = 0 m_sc = 0 c_asb = 0.0 c_wt = 0.0 m_wt = 0.0 c_lq_t = 0.0 lq_t = 0.0 m_sys = 0.0 c_sys = 0.0 c_sc_t = 0.0 sc_t = 0.0 ' ' 乱数の初期設定 ' rn = new Random() ' ' 最初の客の到着時間の設定 ' at = p_time + Next_at() End Sub '********************************' ' 次の客の到着までの時間の発生 ' '********************************' Function Next_at() Return -m_a * Math.Log(rn.NextDouble()) End Function '**********************' ' サービス時間の発生 ' '**********************' Function Next_sv() Return -m_s * Math.Log(rn.NextDouble()) End Function '************' ' 全体の制御 ' '************' Sub Control() Dim sw As Integer = 0 Do While sw > -2 sw = Next_e() ' 次の処理の選択 If sw = -1 sw = End_o_s() ' シミュレーションの終了 Else If sw = 0 Arrive() ' 客の到着処理 Else Service(sw) ' サービスの終了 End If End If Loop End Sub '************************************************' ' 次の処理の決定 ' ' return : =-1 : シミュレーションの終了 ' ' =0 : 客の到着処理 ' ' =i : i番目の窓口のサービス終了 ' '************************************************' Function Next_e() Dim sw As Integer = -1 Dim t As Double = end_s ' シミュレーション終了時刻で初期設定 ' 次の客の到着時刻 If at >= 0.0 and at < t sw = 0 t = at End If ' サービス終了時刻 For i1 As Integer = 0 To s-1 If sb(i1) > 0 and st_e(i1) <= t sw = i1 + 1 t = st_e(i1) ' 窓口i1のサービス終了時刻 End If Next Return sw End Function '********************************' ' 終了処理 ' ' return : =-1 : 終了前処理 ' ' =-2 : 実際の終了 ' '********************************' Function End_o_s() Dim sw As Integer = -2 p_time = end_s ' 現在時刻 at = -1.0 ' 次の客の到着時刻 For i1 As Integer = 0 To s-1 If sb(i1) > 0 ' サービス中の客はいるか? If sw = -2 sw = -1 end_s = st_e(i1) ' 窓口i1のサービス終了時刻 Else If st_e(i1) > end_s end_s = st_e(i1) ' 窓口i1のサービス終了時刻 End If End If End If Next Return sw End Function '**************************' ' 客の到着処理 ' ' ct : 客リストの先頭 ' '**************************' Sub Arrive() ' ' 客数の増加と次の客の到着時刻の設定 ' nc += 1 ' 到着客数カウンタ p_time = at ' 現在時刻 at = p_time + Next_at() ' 次の客の到着時刻 If at >= end_s at = -1.0 End If ' ' 系内客数の処理 ' c_sc_t += cus.Count * (p_time - sc_t) ' 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time ' 現在の系内客数になった時刻 If cus.Count+1 > m_sc m_sc = cus.Count + 1 ' 最大系内客数 End If ' ' 窓口に空きがない場合 ' If asb = 0 Dim ct_p As Customer = new Customer(-1, p_time) cus.Add(nc, ct_p) ' 客の登録(系内客数) c_lq_t += que.Count * (p_time - lq_t) ' 待ち行列長にその長さが継続した時間を乗じた値の累計 que.Enqueue(nc) ' 客の登録(待ち行列) lq_t = p_time ' 現在の待ち行列長になった時刻 If que.Count > m_lq m_lq = que.Count ' 最大待ち行列長 End If ' ' すぐサービスを受けられる場合 ' Else Dim k As Integer = -1 Dim i1t As Integer = 0 Do While i1t < s and k < 0 If sb(i1t) = 0 Dim ct_p As Customer = new Customer(i1t, p_time) cus.Add(nc, ct_p) ' 客の登録(系内客数) k = i1t sb(k) = nc ' サービスを受けている客番号 st_e(k) = p_time + Next_sv() ' 窓口kのサービス終了時刻 asb -= 1 ' 空いている窓口数 End If i1t += 1 Loop st_s(k) = p_time ' 窓口kがふさがった時刻 If asb = 0 asb_t = p_time ' すべての窓口がふさがった時刻 End If End If End Sub '*******************************' ' サービス終了時の処理 ' ' k : サービス終了窓口番号 ' ' ct : 客リストの先頭 ' '*******************************' Sub Service(k As Integer) ' ' 時間の設定 ' k -= 1 p_time = st_e(k) ' 現在時刻 st_e(k) = -1.0 ' サービス終了時間 ' ' 系内客数の処理 ' c_sc_t += cus.Count * (p_time - sc_t) ' 系内客数にその数が継続した時間を乗じた値の累計 sc_t = p_time ' 現在の系内客数になった時刻 ' ' 滞在時間の処理 ' Dim ct As Customer = cus(sb(k)) Dim x1 As Double = p_time - ct.time c_sys += x1 ' 滞在時間の累計 If x1 > m_sys m_sys = x1 ' 最大滞在時間 End If cus.Remove(sb(k)) ' 客の削除(系内客数) ' ' 窓口使用時間の処理 ' asb += 1 ' 空いている窓口数 sb(k) = 0 ' 窓口kを空き状態にする c_sb(k) += (p_time - st_s(k)) ' 窓口kがふさがっている時間の累計 ' ' 待ち行列がある場合 ' If que.Count > 0 asb -= 1 ' 開いている窓口数 c_lq_t += que.Count * (p_time - lq_t) ' 待ち行列長にその長さが継続した時間を乗じた値の累計 Dim n As Integer = que.Dequeue() ' 客の削除(待ち行列) lq_t = p_time ' 現在の待ち行列長になった時刻 ct = cus(n) x1 = p_time - ct.time c_wt += x1 ' 待ち時間の累計 If x1 > m_wt m_wt = x1 ' 最大待ち時間 End If k = -1 Dim i1t As Integer = 0 Do While i1t < s and k < 0 If sb(i1t) = 0 k = i1t sb(k) = n ' 窓口kの客番号 st_e(k) = p_time + Next_sv() ' 窓口kのサービス終了時刻 st_s(k) = p_time ' 窓口kがふさがった時刻 ct.state = k ' 客の状態変更 End If i1t += 1 Loop ' ' 待ち行列がない場合 ' Else If asb = 1 c_asb += (p_time - asb_t) ' すべての窓口がふさがっている時間の累計 End If End If End Sub '**********************' ' 結果の出力 ' ' (カッコ内は理論値) ' '**********************' Sub Output() Dim rn As Double = nc Dim rs As Double = s Dim ram As Double = 1.0 / m_a Dim myu As Double = 1.0 / m_s Dim rou As Double = ram / (rs * myu) Dim p0 As Double Dim pi As Double If s = 1 p0 = 1.0 - rou pi = rou Else p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))) pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)) End If Dim Lq As Double = pi * rou / (1.0 - rou) Dim L As Double = Lq + rs * rou Dim Wq As Double = Lq / ram Dim W As Double = Wq + 1.0 / myu Console.WriteLine("シミュレーション終了時間=" & p_time & " 客数=" & nc & " ρ=" & rou & " p0=" & p0) Console.WriteLine(" すべての窓口が塞がっている割合=" & (c_asb/p_time) & " (" & pi & ")") Console.WriteLine(" 各窓口が塞がっている割合") For i1 As Integer = 0 To s-1 Console.WriteLine(" " & (i1+1) & " " & (c_sb(i1)/p_time)) Next Console.WriteLine(" 平均待ち行列長=" & (c_lq_t/p_time) & " (" & Lq & ") 最大待ち行列長=" & m_lq) Console.WriteLine(" 平均系内客数 =" & (c_sc_t/p_time) & " (" & L & ") 最大系内客数 =" & m_sc) Console.WriteLine(" 平均待ち時間 =" & (c_wt/rn) & " (" & Wq & ") 最大待ち時間 =" & m_wt) Console.WriteLine(" 平均滞在時間 =" & (c_sys/rn) & " (" & W & ") 最大滞在時間 =" & m_sys) End Sub End Class '**********************' ' クラスCustomerの定義 ' '**********************' Class Customer Public time As Double ' 到着時刻 Public state As Integer ' 客の状態 ' =-1 : 待ち行列に入っている ' >=0 : サービスを受けている窓口番号 '*****************' ' コンストラクタ ' ' n : 客番号 ' ' s : 状態 ' '*****************' Public Sub New(s As Integer, t As Double) time = t state = s End Sub End Class End Module
情報学部 | 菅沼ホーム | 目次 | 索引 |