1

I have to assign a certain amount of objects (based on percentage) that have been randomly assigned a true value for a paid subscription attribute, which then get sorted by priority and arrival time in a priority queue. Currently what I have would assign only the first arriving callers a subscribed (true) status and can't seem to think of an easy way to randomize which callers are paid and which are not since each call object is generated sequentially in a for loop.

For example: If there is an average of 25 callers per hr, 25% of them are subscribed and the simulation is for 24 hrs, I would generate 600 callers, 150 subscribed and 450 unsubscribed and randomly assign the 150 subscribed = true

I think I would need to change my for loop range limit to n, then randomly generate a true or false value for bool subscribed within the for loop, but also keep track of how many are iterations are true and false for bool subscribed, which I tried to implement below and still get a random amount of true/false.

Main

    CallCenter dRus; 
    Rep r1;
    bool subscribed = false;
    int percentSubscribed = 0;
    int numSubscribed;
    int numNotSubscribed;
    int countSubbed;
    int countNotSubbed;
    int n;


    n = 24;
    numSubscribed = (percentSubscribed / 100) * n;
    numNotSubscribed = n - numSubscribed;

    for (int i = 0; i <n; i++) //start sim by creating subscribed and unsubscribed callers 
    {
        subscribed = rand() % 2;
        if (subscribed == true) { countSubbed++; }
        else { countNotSubbed++; };
        
        if ((countSubbed > numSubscribed) )
        {
            subscribed = false;
            dRus.generateCalls(subscribed);
        }
        else {dRus.generateCalls(subscribed);};

        
    }

    subscribed = false;
    for (int i = 0; i < numNotSubscribed; i++) //create not subscribed callers
    {
        dRus.generateCalls(subscribed);
    }

Call Center

void CallCenter::generateCalls(bool subbed) //create a call object
{   
    Caller cust(subbed); 
    cust.generateInterArrivalTime();                //generate an inter-arrival time for the the call
    cust.setArrivalTime(cust.getInterArrivalTime()+ clock);    //set the arrival time 
    clock += cust.getInterArrivalTime();                      // update the clock variable 
    callQ.push(cust); //put the call in the queue
}
mrsazonn
  • 57
  • 4

2 Answers2

0

It seems that your problem (of choosing S subscribers among C callers) can be solved as follows:

  1. Create an array of C items, where C is the number of callers. The array's items are 0, 1, ..., N − 1, and indicate the positions (starting from 0) of the corresponding callers.
  2. Shuffle the array of items (C++11 and later has a shuffle method for this purpose). Using rand() (especially rand() % 2) is not the best course of action, especially in C++. See these questions: Why is the use of rand() considered bad?, Generating a random bit - lack of randomness in C rand().
  3. Take the first S items of the shuffled array, and assign the value true to the callers at those positions.
  4. Assign the value false to the remaining callers.
Peter O.
  • 32,158
  • 14
  • 82
  • 96
  • [std::iota](https://en.cppreference.com/w/cpp/algorithm/iota) helps with step 1, and [std::fill](https://en.cppreference.com/w/cpp/algorithm/fill) with 3 and 4 – Caleth Jul 29 '20 at 09:00
0

It appers to me that you want exactly 15% of output so you might do this :

std::mt19937 g{ std::random_device{}() };
auto sz = callers.size();
std::uniform_int_distribution<int> dist(0, sz - 1);

// force exaclty N_percent_subscriber
for(int i = 0; i < (sz * N_percent_subscriber) / 100; ++i ) {
    int pos = dist(g); // get a 'true' random between 0 and sz-1
    while ( callers[pos % sz].subscriber ) {  // if pos already subscriber
        ++pos;                                // keep searching for next non subscriber 
    }
    callers[pos % sz].subscriber = true;
}

https://godbolt.org/z/jfajcE