当前位置:嗨网首页>书籍在线阅读

32-ATM模拟

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

12.7.3 ATM模拟

现在已经拥有模拟ATM所需的工具。程序允许用户输入3个数:队列的最大长度、程序模拟的持续时间(单位为小时)以及平均每小时的客户数。程序将使用循环——每次循环代表1分钟。在每分钟的循环中,程序将完成下面的工作。

1.判断是否来了新的客户。如果来了,并且此时队列未满,则将它添加到队列中,否则拒绝客户入队。

2.如果没有客户在进行交易,则选取队列的第一个客户。确定该客户的已等候时间,并将wait_time计数器设置为新客户所需的处理时间。

3.如果客户正在处理中,则将wait_time计数器减1。

4.记录各种数据,如获得服务的客户数目、被拒绝的客户数目、排队等候的累积时间以及累积的队列长度等。

当模拟循环结束时,程序将报告各种统计结果。

一个有趣的问题是,程序如何确定是否有新的客户到来。假设平均每小时有10名客户到达,则相当于每6分钟有一名客户。程序将计算这个值,并将它保存在min_per_cust变量中。然而,刚好每6分钟来一名客户不太现实,我们真正(至少在大部分时间内)希望的是一个更随机的过程——但平均每6分钟来一名客户。程序将使用下面的函数来确定是否在循环期间有客户到来:

bool newcustomer(double x)
{
    return (std::rand() * x / RAND_MAX < 1);
}

其工作原理如下:值RAND_MAX是在cstdlib文件(以前是stdlib.h)中定义的,是rand()函数可能返回的最大值(0是最小值)。假设客户到达的平均间隔时间x为6,则rand()* x /RAND_MAX的值将位于0到6之间。具体地说,平均每隔6次,这个值会有1次小于1。然而,这个函数可能会导致客户到达的时间间隔有时为1分钟,有时为20分钟。这种方法虽然很笨拙,但可使实际情况不同于有规则地每6分钟到来一个客户。如果客户到达的平均时间间隔少于1分钟,则上述方法将无效,但模拟并不是针对这种情况设计的。如果确实需要处理这种情况,最好提高时间分辨率,比如每次循环代表10秒钟。

程序清单12.12给出了模拟的细节。长时间运行该模拟程序,可以知道长期的平均值;短时间运行该模拟程序,将只能知道短期的变化。

程序清单12.12 bank.cpp

// bank.cpp -- using the Queue interface
// compile with queue.cpp
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime>   // for time()
#include "queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x);      // is there a new customer?
int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::ios_base;
// setting things up
    std::srand(std::time(0));    // random initializing of rand()
    cout << "Case Study: Bank of Heather Automatic Teller\n";
    cout << "Enter maximum size of queue: ";
    int qs;
    cin >> qs;
    Queue line(qs);              // line queue holds up to qs people
    cout << "Enter the number of simulation hours: ";
    int hours;                   // hours of simulation
    cin >> hours;
    // simulation will run 1 cycle per minute
    long cyclelimit = MIN_PER_HR * hours; // # of cycles
    cout << "Enter the average number of customers per hour: ";
    double perhour;      // average # of arrival per hour
    cin >> perhour;
    double min_per_cust; // average time between arrivals
    min_per_cust = MIN_PER_HR / perhour;
    Item temp;           // new customer data
    long turnaways = 0;  // turned away by full queue
    long customers = 0;  // joined the queue
    long served = 0;     // served during the simulation
    long sum_line = 0;   // cumulative line length
    int wait_time = 0;   // time until autoteller is free
    long line_wait = 0;  // cumulative time in line
// running the simulation
    for (int cycle = 0; cycle < cyclelimit; cycle++)
    {
        if (newcustomer(min_per_cust)) // have newcomer
        {
            if (line.isfull())
                turnaways++;
            else
            {
                customers++;
                temp.set(cycle);    // cycle = time of arrival
                line.enqueue(temp); // add newcomer to line
            }
        }
        if (wait_time <= 0 && !line.isempty())
        {
            line.dequeue (temp);      // attend next customer
            wait_time = temp.ptime(); // for wait_time minutes
            line_wait += cycle - temp.when();
            served++;
        }
        if (wait_time > 0)
            wait_time--;
        sum_line += line.queuecount();
    }
// reporting results
    if (customers > 0)
    {
        cout << "customers accepted: " << customers << endl;
        cout << " customers served: " << served << endl;
        cout << " turnaways: " << turnaways << endl;
        cout << "average queue size: ";
        cout.precision(2);
        cout.setf(ios_base::fixed, ios_base::floatfield);
        cout << (double) sum_line / cyclelimit << endl;
        cout << " average wait time: "
             << (double) line_wait / served << " minutes\n";
    }
    else
        cout << "No customers!\n";
    cout << "Done!\n";
    return 0;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
    return (std::rand() * x / RAND_MAX < 1);
}

注意: 编译器如果没有实现bool,可以用int代替bool,用0代替false,用1代替true;还可能必须使用stdlib.h和time.h代替较新的cstdlib和ctime;另外可能必须自己来定义RAND_MAX。

下面是程序清单12.10~程序清单12.12组成的程序长时间运行的几个例子:

Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 15
customers accepted: 1485
  customers served: 1485
         turnaways: 0
average queue size: 0.15
 average wait time: 0.63 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 30
customers accepted: 2896
  customers served: 2888
         turnaways: 101
average queue size: 4.64
 average wait time: 9.63 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 20
Enter the number of simulation hours: 100
Enter the average number of customers per hour: 30
customers accepted: 2943
  customers served: 2943
         turnaways: 93
average queue size: 13.06
 average wait time: 26.63 minutes
Done!

注意,每小时到达的客户从15名增加到30名时,等候时间并不是加倍,而是增加了15倍。如果允许队列更长,情况将更糟。然而,模拟没有考虑到这个事实——许多客户由于不愿意排很长的队而离开了。

下面是该程序的另外几个运行示例。从中可知,即使平均每小时到达的客户数不变,也会出现短期变化。

Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 4
Enter the average number of customers per hour: 30
customers accepted: 114
  customers served: 110
         turnaways: 0
average queue size: 2.15
 average wait time: 4.52 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 4
Enter the average number of customers per hour: 30
customers accepted: 121
  customers served: 116
         turnaways: 5
average queue size: 5.28
 average wait time: 10.72 minutes
Done!
Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 4
Enter the average number of customers per hour: 30
customers accepted: 112
  customers served: 109
         turnaways: 0
average queue size: 2.41
 average wait time: 5.16 minutes
Done!