Generating a random sequence of certain numbers in a deterministic time [duplicate] - c++

This question already has answers here:
How to shuffle a std::vector?
(6 answers)
Closed 8 years ago.
I have written the following piece of code to generate a random sequence of certain numbers {0,1,2,...,31}. It works fine, however, it cannot be guaranteed to complete within any finite amount of time; after any interval there is still only a certain (very high) probability that it will have completed.
Any suggestion for removing this issue?
int th;
vector<int> V2 = vector<int> (32,0);
for (int k=0;k<32;k++){
do{
th = rand() % 32;
} while ( V2[th] == 0 );
V2[th] = k;
}

And an actual implementation:
int a[] = { 0, 1, 2, ....., 31 };
std::random_shuffle(a, a + 32);
or with vectors:
std::vector<int> v(a, a + 32); // from previous snippet
std::random_shuffle(v.begin(), v.end());
In addition, as usually, don't forget to seed the PRNG if you want true-ish random permutations.

Populate a vector with the numbers between zero and 31, and then use a linear-time random shuffle algorithm, such as Fisher-Yates.

Related

Create Array as Vector with 10 Million elements and assign random numbers without duplicates

I try to code myself a Table with random generated Numbers. While that is simple as it is, causing that Vector not having any duplicates isn't as easy as I thought. So far my Code looks like that:
QStringList generatedTable;
srand (QTime::currentTime().msec());
std::vector<int> array(10000000);
for(std::size_t i = 0; i < array.size(); i++){
array[i] = (rand() % 10000000000)+1;
}
It generates numbers just fine, but because I'm generating a large amount of array elements (10 Million), even though I'm using 10 Billion possible numbers, it will create duplicates. I already browsed a bit and found something that seems handy to use, but doesn't work properly in my Program. The code is from another stackoverflow User:
#include<iostream>
#include<algorithm>
#include<functional>
#include<set>
int main()
{
int arr[] = {0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1};
std::set<int> duplicates;
auto it = std::remove_if(std::begin(arr), std::end(arr), [&duplicates](int i) {
return !duplicates.insert(i).second;
});
size_t n = std::distance(std::begin(arr), it);
for (size_t i = 0; i < n; i++)
std::cout << arr[i] << " ";
return 0;
}
It basically moves all the duplicates to the end of the Array, but for some reason does it not work anymore when the array gets bigger. The code will always place the iterator n at 32.768 as long the Array stays above a Million. Under a Million it drops slightly to ~31.000. So while the code is nice it doesn't really help me alot. Does someone have a better option I could use? Since I'm still a Qt and C++ beginner do I not know how to solve that problem properly.
If you want to sample N integers without replacement from the range [low, high) you can write this:
std::vector<int> array(N); // or reserve space for N elements up front
auto gen = std::mt19937{std::random_device{}()};
std::ranges::sample(std::views::iota(low, high),
array.begin(),
N,
gen);
std::ranges::shuffle(array, gen); // only if you want the samples in random order
Here's a demo.
Note that this requires C++20, otherwise the range to be sampled from can't be generated lazily, which would require it to be stored in memory. If you want to write something similar before C++20, you can use the range-v3 library.
The simplest but at the same time most efficient thing is to implement a binary search tree. Generate the random number in your range and check if it's not already there. Note that the operations are performed in a time O(n)

Generation of random number(within a limit) code overshooting the upper limit [duplicate]

This question already has answers here:
Random number c++ in some range [duplicate]
(6 answers)
Closed 6 years ago.
My Computer science C++ book says that to generate random numbers with a lower limit (in this case, 15)and upper limit(in this case, 50), we have to use the following code. But when I used it I got the output as 56,32,49,15. Is there a reason why the program is giving results that overshoot the upper limit or is the code wrong.
#include <iostream>
#include <stdlib.h>
using namespace std;
int main(){
int i,rdno;
for(i=1;i<5;++i){
rdno=(rand()%50)+15;
cout <<rdno<<endl;
}
return 0;
}
If you want to generate a number in [a;b) use
rdno = rand() % (b-a) + a
Here: rdno = (rand()%50) you assign a pseudo-random number from 0-49. If you add 15, you get numbers from 15 to 64. If you want the numbers from 15 to 50, you can do it for example like this: rdno = (rand()%36) + 15.
EDIT: You need to use %36, as the highest number you want is 50. You can get it, when rand() generates 35, then 35%36 equals 35, and 35+15 equals 50. If you used %35, the highest number you can get is 49.
The best way to generate a random number in C that is between [x, y] such that y < 32768 is the following:
int random(int low, int high) {
return rand() % (high - low + 1) + low;
}
Notice the +1 at the modulus operator, this is to allow inclusion of 50. Without it, your range becomes [15, 50).
Sample run: http://ideone.com/Q6l0e5
For a C++ solution, please look at this: std::unfirom_int_distribution
Because the result of rand() % 50 is added to 15. So your range is 15-65.
Your range really is 35 (or 36 if inclusive) so you could change it to:
15 + (rand() % 35)
But really though, if you have access to C++11 use <random>:
#include <random>
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> dis(15, 50);
int random_integer = dis(rng);

generate random number in a range c++ [duplicate]

This question already has answers here:
How does modulus and rand() work?
(4 answers)
Closed 8 years ago.
I'm using the ncurses library to build a game. I'm having trouble generating the correct random numbers. The while loop below needs to keep generating random numbers until they are between 1 and 45(this is my y-axis limits on the standard screen). I can't figure out what I'm doing wrong because the while loop condition looks fine to me. The problem is that while loop starts running infinitely. Im not doing anything but printing the generated numbers at the end as i just want to see that the correct numbers are generated. can anyone please help me with this problem? The following is my int main.
int main()
{
int r,c,x=0;
initscr();
raw();
keypad(stdscr, TRUE);
noecho();
//mvprintw(22,45,"<");
getmaxyx(stdscr,r,c);
int n,n2 = 0;
while((n<1)||(n>45)){
srand (time(NULL));
n = rand();
srand (time(NULL));
n2 = rand();
}
mvprintw(4,10,"First Random Number: %d\n", n);
mvprintw(5,10,"Second Random number: %d\n", n2);
getch();
endwin();
return 0;
}
This is how you can do it in C++:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 gen( rd());
std::uniform_int_distribution<> dis( 1, 45);
for (int n=0; n<1000; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
Using rand() % x is a flawed design because of the bias introduced be dividing a range not evenly. You can read this to learn more about the bias introduced by rand() % x.
You want to call srand once at the start of things and then use modulus to bring rand results into your range, something like:
srand(time(NULL));
n = rand() % 45 + 1;
n2 = rand() % 45 + 1;
Just like #unholySheep commented, rand() returns a value between 0 and RAND_MAX, which it a huge value. Therefore, it is very unlikely you will get quickly a value between 1 and RAND_MAX.
Therefore, the solution is to do the reminder of the division by the number you want:
n = 1 + rand() % 45;
You do not even need a while.
You can get a random number between 1 and 45 inclusive with:
n = rand() % 45 + 1;
It won't be perfect in terms of distribution but it'll be close enough for anyone who's neither a statistician nor a cryptographer, in which case you probably would be using real random numbers.
You should also call srand() once, at the start of your program somewhere, rather than multiple times, especially if you're using the current time to seed it.
Doing it multiple times within the same second will give you a decidedly non-random sequence such as:
42, 42, 42, 42, 42, 42, 42, ...

Use entire list in pseudo-random number generation [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Pseudo-Random Traversal of a Set
I'm trying to write an algorithm that will put the songs of a playlist into a random order, so if there are 10 songs, I need the random number generator to hit every value from 0-9 before repeating. Using the algorithm: x_current = (a * x_prev + c) mod m, is there any way to achieve this with certain values for a c and m?
Try using std::random_shuffle
vector<int> playOrder;
// set some values:
for (int i=1; i<10; ++i) playOrder.push_back(i); // 1 2 3 4 5 6 7 8 9
// Don't forget to seed, or mix will be the same each run
srand(time(NULL));
// using built-in random generator:
random_shuffle ( playOrder.begin(), playOrder.end() );
// An example of how you might use the new random array.
for(int i=0; i<playOrder.size(); i++)
player.PlayTrack(playOrder[i]);
Take a look at this question. Also, for small playlists, simply shuffling an array with the song numbers will be sufficient.

Generate random number between 1 and 3 in C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generating random integer from a range
I just started learning C++ and I'm trying to generate a random integer thats either 1, 2, or 3. I searched around and all the examples I see of generating random numbers are confusing and always different from the last example I looked at. Is there a simple way to do this?
The modulo solution is the most straightforward but it usually loses randomness as modulo as the tendency to "eat up" the lowest bits of the result.
A more random way is to map [0,1[ over [a,b[ in a linear way:
int roll(int min, int max)
{
// x is in [0,1[
double x = rand()/static_cast<double>(RAND_MAX+1);
// [0,1[ * (max - min) + min is in [min,max[
int that = min + static_cast<int>( x * (max - min) );
return that;
}
A generic version is trivially derived from these to get a roll( T min, T max) version.
Try this:
srand(time(NULL));
int randNum = (rand() % 3) + 1; // you don't need the (...) surrounding rand() % 3 but it helps for clarity
This works by taking the remainder of the return value of the rand function divided by three (which can be 0, 1, or 2) and adding one (to come up with either 1, 2, or 3).
Make sure you include the cstdlib and ctime headers.
Also, call srand only one time, not each time you generate a random number.