Using element in vector as index in array? - c++

I'm writing code that randomly generates a vector of indices, fetches a random one, then uses that index to fetch another index, and so on. However, my code seems to repeat a cycle of indices. Here is my full code:
vector<uint16_t>* genBuffer() {
vector<uint16_t>* buffer = new vector<uint16_t>(256);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distr(0, 255);
for (uint16_t i = 0; i < 256; i++) {
(*buffer)[i] = distr(gen);
}
shuffle(buffer->begin(), buffer->end(), gen);
return buffer;
}
double timeAccess(vector<uint16_t>* buff, uint64_t buffSize) {
struct timespec start, stop;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distr(0, 255);
auto index = distr(gen);
auto nextIndex = (*buff)[index];
clock_gettime(CLOCK_MONOTONIC, &start);
for (uint64_t i = 0; i <= buffSize; i++) {
cout << nextIndex << endl;
nextIndex = (*buff)[nextIndex];
}
clock_gettime(CLOCK_MONOTONIC, &stop);
double time_taken = (stop.tv_sec - start.tv_sec) - (double)(stop.tv_nsec - start.tv_nsec);
double avgTime = time_taken/buffSize;
return avgTime;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cout << "Please enter only one numerical argument." << endl;
return -1;
}
uint64_t buffSize = atoi(argv[1]);
auto randBuff = genBuffer();
auto timeTaken = timeAccess(randBuff, buffSize);
cout << "Average time per buffer read = " << timeTaken << " ns" << endl;
return 0;
}
Here is an example run with an argument of 25:
35
218
157
9
4
214
225
246
123
92
195
114
200
33
138
13
17
35
218
157
9
4
214
225
246
123
As you can see, the pattern eventually repeats, although it shouldn't do that.
This code is part of a cache benchmark I was asked to write for class. Here is the full code for anyone willing to try:
https://github.com/aabagdi/CacheBenchmark
As well, I'm trying to time the average time per read in ns. Am I doing that correctly? Thanks!

The generation of your traversal vector is flawed, and can easily generate loops. An example of what you're actually trying to generate for maximal traversal is similar to an interesting (albeit outdated) interview question concerning dropping a stack of bus tickets, each of which has a starting city, ending city, and as a city pair is unique among all others.
Consider holding four tickets, each of which goes from some city Sn to some other city Sm.
S4->S2
S1->S5
S3->S4
S5->S3
the proper order can be thought of like this:
S1->S5
S5->S3
S3->S4
S4->S2
The only difference here is that you need to get back from S2 to S1 if needed, since you don't really know where you're starting from. By adding one faux ticket, S2->S1, you can produce a maximal loop.
S1->S5
^ S5->S3
| S3->S4
| S4->S2
| S2->S1-\
| /
\----------------------
Now it doesn't matter where you start from; eventually you'll hit every city and be back where you started (to do it again if you want).
One way to do that is by building a pairing sequence, then patching in the final return-to-origin as a last step. First, n indexes, build an index array of values 0..(n-1).
// build index vector and shuffle
std::vector<uint16_t> idx(n);
std::iota(idx.begin(), idx.end(), 0);
std::mt19937 gen{ std::random_device{}() };
std::shuffle(idx.begin(), idx.end(), gen);
This is the rock on which we will build our church. We're going to traverse this random ordered sequence, and store the i+1'th index in the i'th slot of our final result. Like this:
// build chain
std::vector<uint16_t> result(n);
for (size_t i=0; i<(n-1); ++i)
result[idx[i]] = idx[i+1];
Finally, the last step is to link the last element of this chain to the initial element of the chain (wherever it is).
// set loop
result[idx[n-1]] = idx[0];
That's it. Now, it doesn't matter where you start in result, it will eventually lead to touching each index before returning to your starting point where it loops (maximally).
The full genBuffer looks like this:
std::vector<uint16_t> genBuffer(size_t n)
{
// build index vector and shuffle
std::vector<uint16_t> idx(n);
std::iota(idx.begin(), idx.end(), 0);
std::mt19937 gen{ std::random_device{}() };
std::shuffle(idx.begin(), idx.end(), gen);
// build chain
std::vector<uint16_t> result(n);
for (size_t i=0; i<(n-1); ++i)
result[idx[i]] = idx[i+1];
// set loop
result[idx[n-1]] = idx[0];
return result;
}
To prove this actually works, a simple test harness to generate a 32-element chain with a maximal loop.
int main()
{
auto randBuff = genBuffer(32);
// pick some random starting point.
std::mt19937 gen{ std::random_device{}() };
std::uniform_int_distribution<size_t> dist(0, randBuff.size()-1);
auto idx = dist(gen);
for (size_t i=0; i<randBuff.size(); ++i)
{
std::cout << idx << " -> " << randBuff[idx] << '\n';
idx = randBuff[idx];
}
}
Output (varies, obviously)
19 -> 10
10 -> 21
21 -> 12
12 -> 22
22 -> 28
28 -> 6
6 -> 16
16 -> 1
1 -> 7
7 -> 3
3 -> 27
27 -> 8
8 -> 14
14 -> 15
15 -> 17
17 -> 2
2 -> 9
9 -> 25
25 -> 31
31 -> 5
5 -> 18
18 -> 13
13 -> 29
29 -> 24
24 -> 26
26 -> 4
4 -> 20
20 -> 11
11 -> 0
0 -> 30
30 -> 23
23 -> 19
Note the last production leads to the first production.
In summary, your index vector generation is susceptible to loops. You want a loop, but only one and should be maximal. Doing what I showed above can give you that.

Couple of thoughts
your generate function will generate the same data each time since you do not seed your (p)rng
You randomly pick an entry and then follow the links, why wouldnt there be a loop? WHy not simply print them out and see if there is a loop.
I mean your generate function can create in the list
1,2,3,0
Thats a loop

Related

How do check an array for repeat numbers in c++? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm trying to produce an array with 4 random generated [srand seeded rand()] without any repeats. I'm using a for loop to:
Select a position in the array,
Generate a number,
Assign the number to the currently highlighted position
Check that the assigned number is not equal to a previous entry, as per the following pseudocode.
if no -
Then select the next position in the array and generate a new number
if yes -
Do not move to the next array position and generate a new number again.
repeat until array position 3
This was my attempt:
int operator_selection;
int operator_index[3];
int random_value;
for (operator_selection = 0; operator_selection < 4; operator_selection++)
{
random_value = rand() %4 + 1;
if (random_value = operator_index[0] || operator_index[1] || operator_index[2])
{
(operator_selection - 1);
}
operator_index[operator_selection] = random_value;
cout<<operator_index[operator_selection]<<" ";
if (operator_selection == 3)
{
cout<<endl;
}
}
However when I run the executable I always end up with repeats, so I'm pretty sure the logic behind my first 'if statement' is flawed.
I'm a c++ beginner and this is my 3rd attempt at writing a source file from scratch, so apologies if I've made a silly mistake.
I see several problems in your posted code.
Problem 1
The line
if (random_value = operator_index[0] || operator_index[1] || operator_index[2])
does not do what you are hoping to do. You need to use:
if ( (random_value == operator_index[0]) ||
(random_value == operator_index[1]) ||
(random_value == operator_index[2]) )
Problem 2
Comparing random_value against operator_index[0] and operator_index[1] and operator_index[2] is incorrect. You only need to compare up to operator_index[operator_selection-1].
Problem 3
The line
(operator_selection - 1);
does not change the value of operator_selection. It just evaluates the expression and discards the value.
What you need is a statement that decrements the value of operator_selection. E.g.
--operator_selection;
Problem 4
You need to continue to the next iteration of the loop when you find an existing value.
Here's an updated version of the loop:
for (operator_selection = 0; operator_selection < 4; operator_selection++)
{
random_value = rand() %4 + 1;
bool matchFound = false;
for ( int i = 0; i < operator_selection-1; ++i )
{
if ( random_value == operator_index[i] )
{
matchFound = true;
break;
}
}
if ( matchFound )
{
--operator_selection;
continue;
}
operator_index[operator_selection] = random_value;
cout<<operator_index[operator_selection]<<" ";
}
// Move this out of the loop.
cout<<endl;
Here is a version using std::array and std::random_shuffle:
#include <iostream>
#include <array>
#include <algorithm>
#include <random>
int main()
{
std::array<int, 4> a = {1, 2, 3, 4};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(a.begin(), a.end(), g);
for(auto& i : a)
std::cout << i << " ";
}
Live Demo
This version is more readable and more efficient.
Update: this does not answer the question as it is and does not fit if it's a home-work. But I would leave it here just in the case OP is interested in a better alternative.
First, you need to make your array bigger. As already mentioned, it would be nicer to use a std::array, but I'll stick with the old style one. You define operator_index with a dimension of 3 which only allows for 3 elements (with offsets from 0 to 2). So this needs a dimension of 4.
You should also initialize the contents of the array (or ensure that you never read from uninitialized elements).
Next, for the first random number there is no possibility of a collision. So you can put it directly into the array.
operator_index[0] = rand() %4 + 1;
You can then loop from 1 to 3 for the remaining 3 entries.
You can even go a little further than this. When you have filled the first 3 entries you can directly calculate the last,
operator_index[3] = 10 - operator_index[2] - operator_index[1] - operator_index[0];
(the sum from 1 to 4 is 10, so the last element is 10 - the sum of the first three)
The main problem with your code is this
if (random_value = operator_index[0] || operator_index[1] || operator_index[2])
{
(operator_selection - 1);
}
This does an assignment, not an equality check. It is assigned the logical OR of the first 3 elements. Since you do not initialize the array you will be reading garbage, and the result is probably going to be that random_value will be set to one and the condition will evaluate to true.
(operator_selection - 1) is an operator without side effects. It does not modify operator_selection. Also once you have found a duplicate, you want to start your loop again.
Here's a version that minimizes the looping.
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
int operator_selection;
int operator_index[4] = {0};
int random_value;
srand(time(0));
operator_index[0] = rand() %4 + 1;
for (operator_selection = 1; operator_selection < 3; operator_selection++)
{
random_value = rand() %4 + 1;
if (operator_index[0] == random_value || operator_index[1] == random_value)
{
--operator_selection;
continue;
}
operator_index[operator_selection] = random_value;
}
operator_index[3] = 10 - operator_index[2] - operator_index[1] - operator_index[0];
for(auto& elem : operator_index)
std::cout << elem << " ";
std::cout << "\n";
}
All that said, I still prefer the std::random_shuffle approach, which I would also suggest.
Another trick to is to reverse the lopp one step back if the conditions are not met.
#include <iostream>
#include <ctime>
using namespace std;
int main(void)
{
const int size=100 ;
int arr[100] ;
int i=0;
srand(time(0));
for ( i=0;i<size;i++) {
arr[i]=rand() % size;
for(int j=0; j < i ; j++) if (arr[j] == arr[i]) i--;
}
cout<<" \n\n\n ";
// Loop to display the array arr[ ]
for ( i=0;i<size;i++) cout<<""<<arr[i]<<"\t";
cout<<" \nPress any key to continue\n";
cin.ignore();
cin.get();
return 0;
}
output:
91 71 14 65 12 25 64 98 83 28
99 9 5 0 89 36 95 55 73 90
78 2 52 70 39 63 17 50 7 58
34 84 40 51 20 31 38 32 35 49
61 66 72 92 6 59 41 13 22 23
81 56 1 16 21 62 57 10 11 54
77 86 76 93 4 96 8 33 94 67
29 48 15 82 97 37 26 46 43 80
68 85 60 30 42 53 18 69 45 88
47 79 75 44 24 27 74 3 19 87
Press any key to continue

Getting a set of random number between 2 numbers that have a certain mean. [duplicate]

This question already has answers here:
Get `n` random values between 2 numbers having average `x`
(5 answers)
Closed 6 years ago.
Problem: Getting a set of random numbers between two values that will have a certain mean value.
Let say we getting n number of random number where the number will be between 1 and 100. We have a mean of 25.
My first approach is to have 2 modes where we have aboveMean and belowMean where the first random number is the initial range 1 and 100. Every subsequent number will check the total sum. If the total sum is above the mean, we go to case aboveMean which is then get a random number between 1 and 25. If the total sum is below the mean, we do case belowMean then get a random number between 26 and 100.
I need some idea on how to approach this problem beside the crude get a random number to add it to the total then get the average. If it above the mean in question, we get a random number below the mean and so forth. While it does work, doesn't seem to be the best method.
I'm guessing I should brush up on probability to approach this random number generator.
Let us divide the range into left and right portions. Use a value from the portion at a frequency corresponding to the relative width of the other half.
int Leruce_rand(int min, int mean, int max) {
int r = rand()%(max - min + 1);
if (r < mean) {
// find number in right half
return rand()%(max - mean + 1) + mean;
} else {
// find number in left half
return rand()%(mean - min) + min;
}
Assumes mean is part of the right half. This quick solution likely has small bias.
Given OP's values, roughly, the average of the left half is 12.5 and called 75% of the time. Average of the right is 62.5 called 25% of the time: average 25.
This approach differs from OP's which "Every subsequent number will check the total sum. If the total sum is above the mean, we go to case aboveMean which is then get a random number between 1 and 25." As that absolutely prevents a set of occurrences above or below the mean. With RNG, the value generated should not be biased on the history of previous generated values.
There's literally an infinite number of ways to achieve this. For instance, generate 3 random numbers between 1 and 100 (std::uniform_int_distribution) and take the minimum of those (std::min(a,b,c)).
Obviously, for a mean of 75 you'll need to pick the maximum of 3 numbers.
The benefit of this method is that each outcome is independent of the previous ones. It's completely random.
Take some good distribution and use it. Say, Binomial distribution. Use B(99,24/99),
so sampled values are in the range 0...99, with parameter p equal to 24/99.
So if you have routine which sample from B, then all you need is to add 1
to be in he range 1...100
Mean value for binomial would be p*n, in this case equal to 24. Because you're adding 1, your mean value would be 25 as required. C++11 has binomial RNG in the
standard library
Some code (not tested)
#include <iostream>
#include <random>
int main() {
std::default_random_engine generator;
std::binomial_distribution<int> distribution(99, double(24)/double(99));
for (int i=0; i != 1000; ++i) {
int number = distribution(generator) + 1;
std::cout << number << std::endl;
}
return 0;
}
Assume a fair random(a,b) function (this question should not be about which random function is better) then simply just restrcting ithe ranges that is piced from should be a good start, like;
const int desiredCount = 16;
const int deiredMean = 25;
int sumValues = random(a,b);
int count = 1;
while (count < desriredCount - 1) {
int mean = sumValue/count;
int nextValue = 0;
if (mean < desiredMean) // Too small, reduce probablity of smaller numbers
nextValue = random(a+(desiredMean-mean)/(desriredCount-count),b);
else //too large, reduce probability of larger numbers
nextValue = random(a,b-(mean-desiredMean)/(desriredCount-count));
sumValue += nextValue;
count += 1;
}
int lastValue = desiredMean*desriredCount - sumValue/count;
sumValue += lastValue;
count += 1;
Note: The above is not tested, and my thinking is that the trimming of the upper and lower bound may not be sufficently aggressive to do the trick, but I hope that i will get you going.
Some boundary conditions, such as if you only want 2 numbers and a means of 25 from numbers between 0 and 100, the initial random number cannot be larger than 50, since that makes it impossible to pick the second (last) number -- so if you want the algo to give you exact mean values under all circumstances, then a bit more tweaking is needed.
OP's wants a set of numbers meeting certain criteria.
Consider generating all possible sets of n numbers in the range [min max] and then eliminating all sets but those with the desired mean. Now randomly select one of those sets. This would meet OP's goal and IMO would pass fair randomness tests. Yet this direct approach is potentially a huge task.
Alternatively, randomly generate lots of sets until one is found that meets the mean test.
The below meets OP's requirement of a specified mean without directly biasing the random numbers selected. Certainly not an efficient method when the desired mean is far from the min/max average.
#include <stdio.h>
#include <stdlib.h>
void L_set(int *set, size_t n, int min, int mean, int max) {
assert(n > 0);
assert(min >= 0);
assert(mean >= min);
assert(max >= mean);
size_t i;
long long diff;
long long sum_target = n;
unsigned long long loop = 0;
sum_target *= mean;
int range = max - min + 1;
do {
loop++;
long long sum = 0;
for (i = 1; i < n; i++) {
set[i] = rand() % range + min;
sum += set[i];
}
diff = sum_target - sum; // What does the final number need to be?
} while (diff < min || diff > max);
set[0] = (int) diff;
printf("n:%zu min:%d mean:%2d max:%3d loop:%6llu {", n, min, mean, max, loop);
for (i = 0; i < n; i++) {
printf("%3d,", set[i]);
}
printf("}\n");
fflush(stdout);
}
int main(void) {
int set[1000];
L_set(set, 10, 1, 2, 4);
L_set(set, 16, 1, 50, 100);
L_set(set, 16, 1, 25, 100);
L_set(set, 16, 1, 20, 100);
return 0;
}
Output
n:10 min:1 mean: 2 max: 4 loop: 1 { 4, 2, 4, 3, 2, 1, 1, 1, 1, 1,}
n:16 min:1 mean:50 max:100 loop: 2 { 45, 81, 24, 50, 93, 65, 70, 52, 28, 91, 25, 36, 21, 45, 11, 63,}
n:16 min:1 mean:25 max:100 loop: 3257 { 52, 1, 15, 70, 66, 30, 1, 4, 26, 1, 16, 4, 48, 42, 19, 5,}
n:16 min:1 mean:20 max:100 loop:192974 { 24, 10, 13, 3, 3, 53, 22, 12, 29, 1, 7, 6, 90, 11, 20, 16,}
you have to go into some probabilities theory. there are a lot of methods to judge on random sequence. for example if you lower the deviation you will get triangle-looking-on-a-graph sequence, which can in the end be proven not trully random. so there is not really much choice than getting random generator and discarding the sequences you don't like.
EDIT: this generates numbers in the range 1..100 with a theoretical mean of 25.25. It does this by using a random modulus in the range 1..100. Note that the required mean is 25, which is not exactly a quarter of the range 1..100.
OP wanted a way of varying the next number chosen according to whether the mean is less than or more than 25, but that lends some predictabilty - if the mean is more than 25 then you know the next "random" number will be less than 25.
The random calculation in the code is a very simple one line.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define RUNS 10000000
#define MAXN 100
int main() {
int n, i, sum = 0, min = MAXN, max = 0;
int freq[MAXN+1] = {0};
srand((unsigned)time(NULL));
for(i = 0; i < RUNS; i++) {
n = 1 + rand() % (1 + rand() % 100); // average modulus is (1 + MAX) / 2
if(max < n) {
max = n; // check that whole range is picked
}
if(min > n) {
min = n;
}
freq[n]++; // keep a tally
sum += n;
}
// show statistis
printf("Mean = %f, min = %d, max = %d\n", (double)sum / RUNS, min, max);
for(n = MAXN; n > 0; n--) {
printf("%3d ", n);
for(i = (freq[n] + 5000) / 10000; i > 0; i--) {
printf("|");
}
printf("\n");
}
return 0;
}
Program output showing distribution / 10000:
Mean = 25.728128, min = 1, max = 100
100
99
98
97
96 |
95 |
94 |
93 |
92 |
91 |
90 |
89 |
88 |
87 |
86 ||
85 ||
84 ||
83 ||
82 ||
81 ||
80 ||
79 ||
78 |||
77 |||
76 |||
75 |||
74 |||
73 |||
72 |||
71 ||||
70 ||||
69 ||||
68 ||||
67 ||||
66 ||||
65 ||||
64 |||||
63 |||||
62 |||||
61 |||||
60 |||||
59 |||||
58 ||||||
57 ||||||
56 ||||||
55 ||||||
54 ||||||
53 ||||||
52 |||||||
51 |||||||
50 |||||||
49 |||||||
48 |||||||
47 ||||||||
46 ||||||||
45 ||||||||
44 ||||||||
43 |||||||||
42 |||||||||
41 |||||||||
40 |||||||||
39 ||||||||||
38 ||||||||||
37 ||||||||||
36 ||||||||||
35 |||||||||||
34 |||||||||||
33 |||||||||||
32 ||||||||||||
31 ||||||||||||
30 ||||||||||||
29 |||||||||||||
28 |||||||||||||
27 |||||||||||||
26 ||||||||||||||
25 ||||||||||||||
24 ||||||||||||||
23 |||||||||||||||
22 |||||||||||||||
21 ||||||||||||||||
20 ||||||||||||||||
19 |||||||||||||||||
18 |||||||||||||||||
17 ||||||||||||||||||
16 |||||||||||||||||||
15 |||||||||||||||||||
14 ||||||||||||||||||||
13 |||||||||||||||||||||
12 ||||||||||||||||||||||
11 |||||||||||||||||||||||
10 ||||||||||||||||||||||||
9 |||||||||||||||||||||||||
8 ||||||||||||||||||||||||||
7 |||||||||||||||||||||||||||
6 |||||||||||||||||||||||||||||
5 |||||||||||||||||||||||||||||||
4 |||||||||||||||||||||||||||||||||
3 |||||||||||||||||||||||||||||||||||||
2 ||||||||||||||||||||||||||||||||||||||||||
1 ||||||||||||||||||||||||||||||||||||||||||||||||||||
OP did not state what kind of distribution was wanted, for example two straight lines pivoting at 25, or perhaps equal distribution each side of 25. However this solution is very simple to implement.

How can I generate a random number from 1 - 39 without making a number overlap? [duplicate]

This question already has answers here:
Unique (non-repeating) random numbers in O(1)?
(22 answers)
Closed 8 years ago.
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void randnum()
{
int random;
srand((unsigned int)time(0));
for(int i=1;i<=5;i++)
{
random=(rand()%39)+1;
cout<<random<<endl;
}
}
int main()
{
cout<<"Five random number is here"<<endl;
randnum();
system ("PAUSE");
return 0;
}
I am randomly doing this to practice C++. I always get confused in setting the range of random generator (is my method correct? from 1-39). Also how can I prevent numbers from overlapping one another? That is, if I am outputting 5 different numbers from 1-39, it can always 5 different numbers like 4,5,2,7,12 instead of 4,5,2,4,12 (4 is used twice here)
Yes, the method of getting a random number between 1 and 39 is correct.
To ensure non-overlapping numbers, two algorithms come to mind:
keep a set of already-served numbers and skip when they are picked a second time, or
create a list of all candidate numbers and randomly reorder them, then serve them in order
The method is correct. To prevent numbers from overlapping one another, for me the best solution would be to create a vector of already generated numbers, and every time you generate a new random number, see if it is already in the vector. If it is, regenerate. If it isn't, then add it to the vector and move on.
Try create a vector containing the numbers 1 -39, shuffle them, and pick the first 5. Then you have 5 non-repeating random numbers.
random_shuffle() function is implemented in the C++ library. Check here:
http://www.cplusplus.com/reference/algorithm/random_shuffle/
random=(rand()%39)+1;
This could lead to a duplicate.
I always get confused in setting the range of random generator (is my method correct from 1-39?)
The number of elements in a range [begin,end] (where the bracket means "inclusive") is:
count = end - begin + 1
If you need one of 0-based count elements, then you perform:
rand() % count
Because the starting element may not be 0, you actually perform the following to get a value in the range:
rand() % count + begin
Also how can I prevent numbers from overlapping one another?
In this case, one of the easier solutions would be to use a vector. Its not as efficient as other answers (like the one #Retired Ninja suggested), but its easier to understand. Something like shown below.
The code below just dumps the result of the shuffle (which is not random because it repeats across runs based on the seed used). It should not be hard for you to adapt it to the first 5 elements (we can't give you all the answers).
ShuffledRange range (1, 39);
...
$ ./tt.exe
29 33 8 37 9 32 38 24 16 14 36 7 10 31 34 39 27 11 6 4 35 1 19 20 18 15 5 12 22
21 3 30 17 25 2 28 23 26 13
If you specify a seed (the default is 0), then you will get a different sequence:
ShuffledRange range (1, 39, 2);
...
$ ./tt.exe
12 20 28 6 7 15 32 17 35 11 18 31 27 4 23 36 25 24 22 1 33 2 37 39 21 9 38 13 5 3
14 10 8 34 16 19 29 26 30
The code below needs C++ 11 because of random_shuffle. Visual Studio 2012 should be fine with C++ 11. I'm not sure about Visual Studio 2010.
GCC will need:
$ g++ -Wall -Wextra -std=c++11 tt.cpp -o tt.exe
And Mac OS X:
$ g++ -Wall -Wextra -std=c++11 -stdlib=libc++ tt.cpp -o tt.exe
class ShuffledRange
{
public:
explicit ShuffledRange(unsigned int low, unsigned int high, int seed=0)
: m_numbers(move(create_numbers(low,high,seed))), m_it(m_numbers.begin()) { }
unsigned int GetCount() const {
return static_cast<unsigned int>(m_numbers.size());
}
bool HasNext() const {
return m_it != m_numbers.end();
}
unsigned int GetNext()
{
if(!HasNext())
throw std::runtime_error("No numbers left");
unsigned int temp = *m_it++;
return temp;
}
protected:
vector<unsigned int> create_numbers(unsigned int low, unsigned int high, int seed)
{
if(high < low)
throw std::runtime_error("Bad range of elements");
vector<unsigned int> temp;
temp.reserve(high - low + 1);
for(unsigned int i = low; i <= high; i++)
temp.push_back(i);
srand(seed);
random_shuffle(temp.begin(), temp.end());
return temp;
}
private:
vector<unsigned int> m_numbers;
vector<unsigned int>::iterator m_it;
};
int main(int argc, char* argv[])
{
ShuffledRange range(1, 39);
while(range.HasNext())
cout << range.GetNext() << " ";
cout << endl;
return 0;
}
A hint....
int main()
{
cout<<"Five random number is here"<<endl;
randnum();
system ("PAUSE");
return 0;
}
If you place a breakpoint (F9) on main's closing brace (i.e., the }), then you won't need the system ("PAUSE");. Visual Studio will break and wait for you. Once you've inspected the values, then press F5 to finish the program.

What is the idea of a good random numbers generator?

I am writing a program for card games. There can be several game players (say, from 2 to 7). A deck consists of 54 cards. I need to distribute/deal cards to the players randomly.
We can consider the deck of 54 cards as a char array of 54 elements. Let us suppose that in a certain game each player must be given with 6 cards. The number of players is 2. So, it is necessary to generate two arrays, each of them consists of 6 elements selected from a "big" array of 54 elements. Moreover, in those two generated arrays there should not be shared/duplicate elements.
I tried a recursive algorithm to obtain a sequence of m unique random numbers from 0 to (m - 1).
X(n+1) = (a * X(n) + c) mod m
You need to set the parameters:
m -- module, m > 0
a -- factor, 0 <= a < m
c -- increment, 0 <= c < m
X(0) -- initial value , 0 <= X(0) < m
Numbers c and m must be coprime.
(a - 1) is divisible by p for each prime p that is a divisor of m
If m is divisible by 4 then (a - 1) must be divisible by 4.
Here's the code for this algorithm. As you can see, the parameters a, c, m and X(0) satisfy the mentioned conditions.
int a = 13,
c = 11,
m = 54, // because the total number of cards is 54
x0 = 1;
int x[100];
x[0] = x0;
cout << x[0] << " ";
for (int i = 1; i < m; i++)
{
x[i] = (a * x[i - 1] + c) % m;
cout << x[i] << " ";
}
The result is: 1 24 53 52 39 32 49 0 11 46 15 44 43 30 23 40 45 2 37 6 35 34 21 14 31 36 47 28 51 26 25 12 5 22 27 38 19 42 17 16 3 50
13 18 29 10 33 8 7 48 41 4 9 20. Do you think it is random?
What can you say about this algorithm? In general, what should be the idea of ​​a random distribution of cards for each player?
You see, if I integrate this algorithm to my program, it will deal the same sequence of cards as it is shown above each time you launch the program (because the parameters do not change). So I will need to change a, m, c and X(0) between launches of my program. Then I will have another problem: how to set these parameters automatically (and randomly, too) so that they satisfy the necessary conditions (see the bulleted list above).
It seems to me like you're making an unnecessarily complex system.
A much simpler approach is to create an array of all of your elements, shuffle it, and then just remove elements one at a time.
A simple and efficient way of shuffling is to use a Fisher-Yates shuffle:
//Initialize an array/vector/etc. with all the possible values
for (int i = NUMBER_OF_ELEMENTS-1; i >= 0; i--)
{
//Pick a random integer j between 0 and i (inclusive)
//Swap elements i and j
}
Now, you can just iterate through the shuffled array, picking the next element every time you need a new card.
int pos = 0; //The position of the next card in the deck
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < NUMBER_OF_PLAYERS; j++)
{
player[j].addCard(deck[pos++])
}
}
Ideally, you would probably want to wrap some of this into classes, but I've left that out for brevity.
You cannot guarantee randomness the way you put it. It is a generated sequence with low informational enthropy - in other words it is easily hacked.
You can simply use standard rand() from stdlib http://www.cplusplus.com/reference/cstdlib/rand/.
I'd recommend using mt19937 comes with std in c++11 http://www.cplusplus.com/reference/random/mt19937/ or boost one as mentioned in comments.
another way to do it, could be to randomize the action of taking a card instead of a shuffle the container.
something like this :
// first step
// init and fill container
std::vector<int> v;
for (int i = 0; i < 54; ++i)
v.push_back(i);
// second step
// take a random card
srand(time(NULL)); // init seed
int i = std::rand() % v.size();
int card = v[i]; // get card
v.erase(vec.begin() + i); // remove card from deck
return card;
for the second step, you need <ctime> and <cstdlib>. I am not sure it is better than the other solution. Just my two cents.

Probability of choosing two cities C++

I'm making a program where I have a list of 34 cities and I am wanting to give each of these cities a probability of being chosen.
So I have:
vector<float> vec;
int s;
cin >> s;
srand(s);
for (int k=0; k < 34; k++)
{
float p1= (float)rand()/(float)((unsigned)RAND_MAX+1);
vec.push_back(p1);
}
So that gives each city a probability. The problem I am now having is I want to then do a random number generator that will choose two of these cities. So, for example city1 will have a 5%, city2 a 2%, city3, a 3%, etc. How can I randomly choose two of these cities based off the probabilities given?
I did this in genetic algorithm.
for your cities consider a line of 10 units.
now from 0-5 units on line are city1 6-7 for city2 and 8-9 for city3.
now choose a number at random from 0-9.
and found out in which cities range it comes in.
At first glance my solution will be :
Create a number equals to all city's probability
Create a random number, with max random number is equal to the previous number
Take the random number, and go throught your city vector and take the one who is corresponding.
Example :
City 1 : 5%
City 2 : 8%
City 3 : 2%
City 4 : 5%
City 5 : 12%
Create a number -> Number a = 32 (5+8+2+5+12)
Generate a number with : 1 <= number
Assume that the number is equal to 12
City 1 is choose if : 1 <= number <= 5 (So not)
City 2 is choose if : 6 <= number <= 13 (So yes)
City 2 is choose.
If you have any questions about that, you are welcome :)
Edit :
Well i will give you some more explaination.
Take this code :
for (int k=0; k < 10; k++)
{
float p1= (float)rand()/(float)((unsigned)RAND_MAX+1);
vec.push_back(p1);
}
Assume now that vec contain the following informations :
5
3
8
5
12
14
8
5
6
18
With each number correspond to the probability to choose a city.
5 -> 5% probability to choose (City1)
3 -> 3% probability to choose (City2)
8 -> 8% probability to choose (City3)
... etc
Now i will give you some code and i will explain it :
int nbReference = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
nbReference += *it;
}
nbReference = rand(nbReference);
int i = 0;
int cityProbability = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
cityProbability = *it;
if ((i + cityProbability) > nbReference)
{
return (i + 1);
}
i += cityProbability;
}
First i create a number equals to the addition of all city's probability
int nbReference = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
nbReference += *it;
}
Second, i generate a number that is respect the following range -> 0 < nbReference
Third, i create a loop that take all city one by one and quit when we got right city.
How does we know when a city is good?
Let's take an example!
With our previous probability
5 3 8 5 12 14 8 5 6 18
NbReference is equals to (5+3+8+5+12+14+8+5+6+18) so 84
To each city we are going to put a range equals to his probability plus all of previous city's probability. Let me show you :
5 -> Range 0 to 4 (0 to 4 = 5 ---> 5%)
3 -> Range 5 to 8 (5 to 8 = 3 ---> 3%)
8 -> Range 9 to 17
5 -> Range 18 to 22
... etc
If the number that we create here
nbReference = rand(nbReference);
Is in a city range, so that city is choosed.
Example : If the number is 16, city3 is choosed!
5 -> Range 0 to 4 Number is 16 so NOPE
3 -> Range 5 to 8 Number is 16 so NOPE
8 -> Range 9 to 17 Number is 16 so YES!
5 -> Range 18 to 22
... etc
Does is this helpfull? :)
Any questions? You are welcome
Maybe this code can help you (follows partially WhozCraig advice)
#include <iostream>
#include <random>
#include <algorithm>
int main(int argc, const char * argv[])
{
using namespace std::chrono;
system_clock::time_point tp = system_clock::now();
system_clock::duration dtn = tp.time_since_epoch();
std::default_random_engine generator(static_cast<int>(dtn.count()));
//Generate 34 cities
std::uniform_real_distribution<double> gen_distribution(0,1);
auto getProb = std::bind ( gen_distribution, generator );
std::vector<double> citiesProb;
double probSum(0.0);
double cityProb(0.0);
for (int k=0; k < 34; k++)
{
cityProb = getProb();
probSum += cityProb;
citiesProb.push_back(cityProb);
}
//Pick 7 cities
std::uniform_real_distribution<double> pick_distribution(0,probSum);
auto pickCity = std::bind ( pick_distribution, generator );
double chooseCity;
double probBasket;
for (int k=0; k < 7; ++k)
{
probBasket = 0.0;
chooseCity = pickCity();
for (int i = 0; i < citiesProb.size(); ++i)
{
if (chooseCity >= probBasket && chooseCity < probBasket + citiesProb[i])
{
std::cout << "City with index " << i << " picked" << std::endl;
}
probBasket += citiesProb[i];
}
}
return 0;
}
How it works:
city1 5%(0.05), city2 25%(0.25), city3 8%(0.08), city4 10%(0.1)
then
probSum = 0.05 + 0.25 + 0.08 + 0.1 = 0.48
then choose a number between 0 and 0.48 (named pickProb) and
if pickProb is between 0 and 0.05 pick city1 (prob = 0.05/0.48 = 10%)
if pickProb is between 0.05 and 0.30 pick city2 (prob = 0.25/0.48 = 52%)
if pickProb is between 0.30 and 0.38 pick city3 (prob = 0.08/0.48 = 16%)
if pickProb is between 0.38 and 0.48 pick city4 (prob = 0.1/0.48 = 20%)
if probSum = 1.0 then city1 is picked with probability 5%, city2 is picked with probability 25% and so on.