Choose a random number from a list of integer - c++

I have a list of integers intList = {1, 3. 5. 2} (Its just an example integer and size both are unknown). I have to chose a random number from that list.
RandomInt = rand() % intList.size()
will work in a similar way as RandomInt = rand() % 4
and generate a randon number between 1 to 4. while intList is different.
If I am using RandomInt = std::random_shuffle = (intList, intList.size())
still getting error. I do not know how chose a random number from a list.

Since, as a substep, you need to generate random numbers, you might as well do it the C++11 way (instead of using modulo, which incidentally, is known to have a slight bias toward low numbers):
Say you start with
#include <iostream>
#include <random>
#include <vector>
int main()
{
const std::vector<int> intList{1, 3, 5, 2};
Now you define the random generators:
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> distr(0, intList.size() - 1);
When you need to generate a random element, you can do this:
intList[distr(eng)];
}

You just need to use "indirection":
std::vector<int> list{6, 5, 0, 2};
int index = rand() % list.size(); // pick a random index
int value = list[index]; // a random value taken from that list

int arrayNum[4] = {1, 3, 5, 2};
int RandIndex = rand() % 5; // random between zero and four
cout << arrayNum[RandIndex];

Related

c++ random numbers, evenly distributed

I need to generate random numbers between two values in c++, which can be generated like that(in a range 1 to 6)
:
#include <iostream>
#include <random>
int main(int argc, char* argv[]){
srand(time(NULL));
for (int j = 0; j < 6 ; j++) {
randomNumber = rand() % 6 + 1;
cout << randomNumber;
return 0;
}
But I also need to ensure that it generates at least once each number in the range, for example: range [1,6], you must generate at least once the 1,2,3,4,5 and 6.
And there is another thing, the numbers generated, must be evenly distributed, like if want generate 20 iterations in range of[1,6], each number(1,2,3,4,5,6) should have approximately the same quantity generated at 20 iterations. Example: 1,3,5,2,4,6,2,4,6,1,3,5,6,5,4,3,5,2,1.... and not like this: 1,3,5,6,6,6,2,6,4,4,4,4,4,4...
If anyone knows how to solve this, I'll be very grateful to you.
Thanks!!!
This is where the C++ Standard Library comes to the rescue. Typed off the top of my head:
#include <random>
int get_rand_in_1_6()
{
static std::random_device rnd;
return std::uniform_int_distribution <int> ( rnd )( 1, 6 );
}
The result will be uniformly-distributed.
(You may not get one of each in the first six iterations, though. Being uniformly distributed does not guarantee any specific values in any specific sub-interval, only that the number is just as likely as any other to appear. Given enough iterations, you will see that.)
[edit 2]: IDR the exact mathematical formula for minimum number of iterations to guarantee that you see each number at least once — I am wildly guessing around 15 for the minimum number of pulls to guarantee that.
If I understand correctly, std::shuffle might help you:
std::random_device rd;
std::mt19937 gen(rd());
int numbers[] = {1, 2, 3, 4, 5, 6};
for (int j = 0; j < 20 ; j++) {
if (j % 6 == 0) { std::shuffle(numbers, numbers + 6, gen); }
std::cout << numbers[j % 6];
}
Demo
You have then sequence of random permutations.

Can I exclude a number or subrange of numbers inside a range of random numbers in modern C++?

I have:
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> probability(0, 100);
I want to exclude some numbers in this range of probabilities.
Example 1: Let's say, I want to generate a random number between 0 and 100, but this number can never be 4.
Example 2: Let's say, I want to generate a random number between 0 and 100, but this number can never be any number between 4 and 7.
I wonder if it is possible to achieve in modern C++ without using std::rand?
If you want to stay with a uniform_int_distribution you can do it manually like this:
Example1: Let's say, I want to generate a random number in between 0 and 100, but this number can never be 4.
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> distribution(0,99);
auto temp = distribution(mt);
auto random_number = (temp < 4) ? temp : temp + 1;
Example2: Let's say, I want to generate a random number in between 0 and 100, but this number can never be any number between 4 and 7.
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> distribution(0,96);
auto temp = distribution(mt);
auto random_number = (temp < 4) ? temp : temp + 4;
This could be generalize to write a function random_int_between_excluding(int first, int last, std::vector<int> exclude), though at some point it will be simpler to follow NathanOlivers suggestion and use a std::discrete_distribution instead.
Example2: Let's say, I want to generate a random number in between 0
and 100, but this number can never be any number between 4 and 7.
This is what std::piecewise_constant_distribution is for.
std::vector<int> i{0, 4, 8, 101};
std::vector<int> w{ 4, 0, 93};
std::piecewise_constant_distribution<> d(i.begin(), i.end(), w.begin());
Live demo
If you want to miss out 4 say, then a very good way (which doesn't compromise any statistical properties of the generator), is to draw in the half-open interval [0, 99) then add 1 if the number is 4 or greater.
You do something similar to omit numbers in a range.
This method is a surprisingly good way of modelling the quantile function associated with the desired probability distribution.
You can use a filter of arbitrary complexity on uniform distribution:
template<typename D, typename G, typename F>
auto sample(D &distribution, G &generator, F const &filter)
{
while(true)
{
auto const value = distribution(generator);
if(filter(value))
return value;
}
}
Your example case transforms into the following
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> probability(0, 100);
auto const filter = +[](int n) {return n < 4 || n > 7;}
int const i = sample(probability, mt, filter);
You have to keep in mind that this kind of filtering comes at a cost.
Let N be the number of distinct values the distribution returns, F - the number of these values filtered out; then, if you need to sample S values, you have to sample and filter S * N / (N - F) values at average. It's okay if F is small compared to N, but horribly inefficient when F approaches N. In your case, N = 100, F = 4, and N / (N - F) = 1.04166...
If you care prefer readability and simplicity, that's your choice. Otherwise, if you need performance, you'd better try out piecewise distributions or mess with the value range manually.
There is an option to do it manually within a reasonable range of numbers..., create a look up table and exclude the numbers that are invalid:
static int rand_pool[]{1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; //no number 4
srand((int)time(0));
int random_number = rand_pool[rand() % 22];

Randomly selecting 2 integers not in a range?

I'm new to C++, and I've been searching all day to find a way to randomly select one of two distinct integers.
Everything I've found so far works only for integers within a range (1-10, etc) rather than for (1 or 3).
For ex. code I've been using elsewhere in the program (for a range of numbers) is
int c;
int Min = 1;
int Max = 3;
c = rand() % (Max + 1 - Min) + Min;
which returns a random integer within the range, rather than one or the other integers given.
First of all you shouldn't use C random in C++. Use C++ random.
The way to chose from a set of elements is to randomly generate an index. You can wrap the logic in a class:
#include <random>
#include <iostream>
#include <vector>
#include <initializer_list>
class Random_choice
{
std::random_device rd_{};
public:
template <class T> auto get_choice(std::initializer_list<T> elements) -> T
{
std::uniform_int_distribution<std::size_t> dist{0, elements.size() - 1};
std::size_t i = dist(rd_);
return *(elements.begin() + i);
}
};
int main()
{
Random_choice rc;
std::cout << rc.get_choice({3, 5}) << std::endl;
}
Or without the abstraction:
#include <random>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> choices = {3, 5};
std::random_device rd;
std::mt19937 e{rd()};
std::uniform_int_distribution<std::size_t> dist{0, choices.size() - 1};
std::size_t i = dist(e);
std::cout << choices[i] << std::endl;
}
Randomly choosing one of two integers, a or b:
c = (rand() % 2) ? a : b
Randomly choosing an integer from a list of integers:
std::vector<int> numbers;
c = numbers.at(rand() % numbers.size());
Randomly choosing an integer from two intervals [a, b) and [c, d):
H = (b-a);
L = (b-a) + (d-c);
k = rand() % L;
c = (k < H) ? (a + k) : (c + (k - H));
In case you do C++11 then you may definitely have look into pseudo-random numer generation, like discrete_distribution and uniform_int_distribution.
Update. Removed the claim that we would choose uniformly from the given set. Since rand() chooses from [0, RAND_MAX], this is only true if the divisor of the above modulo operations divides (RAND_MAX+1). (Which is true for the first example in most implementations where RAND_MAX is 32767 or another power-of-two minus 1.) However, the defect from being uniform is roughly of the order of divisor/RAND_MAX. Nevertheless, C++11 uniform_int_distribution is recommended instead. Thanks, Baum mit Augen.
If you have a range of numbers that you don't want numbersin, then you have two ranges that you do want numbers in.
For example, if your range is 1 to 3 (inclusive) then the two ranges you do want numbers in are -∞ to 0, and 4 to ∞.
Infinity is a little tricky on computers, but can easily be emulated for example by std::numeric_limits to get the min and max for the wanted type.
So in your case you want a random number in the range std::numeric_limits<int>::min() to 0, and 4 to std::numeric_limits<int>::max().
Two get two random numbers from a random choice of either range, first pick (randomly) one range, and get a number from that. Then again (randomly) pick a range and get the second number from that.

What is the best way to generate random numbers in C++?

What is the best way to generate random numbers?
You should use <random>:
#include <random>
typedef std::mt19937 rng_type;
std::uniform_int_distribution<rng_type::result_type> udist(0, 7);
rng_type rng;
int main()
{
// seed rng first:
rng_type::result_type const seedval = get_seed(); // get this from somewhere
rng.seed(seedval);
rng_type::result_type random_number = udist(rng);
return random_number;
}
Pre C++11 you could find this either in TR1 (<tr1/random>, std::tr1::mt19937 etc.), or in Boost.random, with essentially the same interface (though there are minor differences).
If and only if:
you are not looking for "perfect uniformity" or
you have no C++11 support and not even TR1 (thus you don't have another choice)
then you might consider using the following C-style solution, which (for the sake of the reputation of this community ~ see rand() Considered Harmful) is written in strike-through font:
Here's the simple C-style function that generates random number from the interval from min to max, inclusive. Those numbers seem to be very close to being uniformly distributed.
int irand(int min, int max) {
return ((double)rand() / ((double)RAND_MAX + 1.0)) * (max - min + 1) + min;
}
and don't forget to call srand before you use it:
int occurrences[8] = {0};
srand(time(0));
for (int i = 0; i < 100000; ++i)
++occurrences[irand(1,7)];
for (int i = 1; i <= 7; ++i)
printf("%d ", occurrences[i]);
output: 14253 14481 14210 14029 14289 14503 14235
Also have a look at:
Generate a random number within range?
Generate random numbers uniformly over an entire range
and find some time and watch at least first 11 minutes of aforementioned video
Otherwise:
use <random> just like it was pointed out by Kerrek SB already.
Boost.Random is an excellent library for producing pseudorandom numbers (or truly random, if the platform supports it).
If you're talking standard C++ library pre C++11, rand and srand are your random number generators. There are ways to get more accuracy out of these functions than using modulus with integer arithmetic. You could use doubles, for example, if high speed isn't a concern and round the results to int.
As for custom libraries, if you really want good random distribution and speed, google Mersenne Twister. There are also options in boost.
With C++11 you have <random>. http://en.cppreference.com/w/cpp/numeric/random
My 'random' library provide a high convenient wrapper around C++11 random classes. You can do almost all things with a simple 'get' method.
Examples:
Random number in a range
auto val = Random::get(-10, 10); // Integer
auto val = Random::get(10.f, -10.f); // Float point
Random boolean
auto val = Random::get<bool>( ) // 0.5% to generate true
auto val = Random::get<bool>( 0.7 ) // 0.7% to generate true
Random value from a std::initilizer_list
auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
Random iterator from iterator range or all container
auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
auto it = Random::get( vec ); // return random iterator
And even more things ! Check out the github page:
https://github.com/effolkronium/random

Biased Random Number Generator

I am looking for a random number generator that can be biased. For instance, say I want a random number between 1-5, with the probability being:
1: Comes up 20% of the time
2: Comes up 10% of the time
3: Comes up 40% of the time
4: Comes up 25% of the time
5: Comes up 5% of the time
Is there anything in the standard library, or other libraries out there that would do this? Alternatively, is there an efficient way to do this myself?
For your problem, just pick a random element from this list uniformly:
[1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5]
In general, check this answer: Weighted random numbers
In TR1 and C++0x, there is <random> header which contains the discrete_distribution class to generate such numbers, among others.
You may also want to check out GSL which contains much more random distributions (and random number generators) than the standard <random> library. (But note that GSL uses GPLv3.)
Best way's probably to just take the normal unbiased random generator then return based on the interval its value falls into.
Just an if statement that gives 1 for 0:0.2, 2 for 0.2:0.3, 3 for 0.3:0.7, 4 for 0.7:0.95 and 5 for 0.95:1. Best to make either the lower or upper limit of the interval inclusive and the other exclusive.
int biasedRandom(){
double i = randomNumber();
if(i<= 0.2){return 1;}
else if(i <= 0.3){return 2;}
else if(i <= 0.7){return 3;}
else if(i <= 0.95){return 4;}
else{return 5;}
}
Something like that.
The Boost random number library provides the ability to specify different shaped distributions for your generator. It's a great library - see http://www.boost.org/doc/libs/1_42_0/libs/random/index.html.
Coming late to the party on this one. Here is the C++0x answer:
#include <iostream>
#include <random>
#include <iterator>
int main()
{
// Set up distribution
double interval[] = {1, 2, 3, 4, 5, 6};
double weights[] = { .2, .1, .4, .25, .05};
std::piecewise_constant_distribution<> dist(std::begin(interval),
std::end(interval),
std::begin(weights));
// Choose generator
std::mt19937 gen; // seed as wanted
// Demonstrate by pouring into avg[rand-1]
const unsigned N = 1000000;
double avg[sizeof(weights) / sizeof(weights[0])] = {0};
for (unsigned i = 0; i < N; ++i)
avg[static_cast<unsigned>(dist(gen)) - 1]++;
// Comute averages
for (double* i = std::begin(avg); i < std::end(avg); ++i)
*i /= N;
// Display
for (unsigned i = 1; i <= sizeof(avg)/sizeof(avg[0]); ++i)
std::cout << "avg[" << i << "] = " << avg[i-1] << '\n';
}
Which for me outputs:
avg[1] = 0.199779
avg[2] = 0.100002
avg[3] = 0.400111
avg[4] = 0.250257
avg[5] = 0.049851
What you are describing is the implementation of a random number generator that draws from a particular probability distribution. For example, drawing numbers from a Gaussian distribution should draw random numbers such that the probability of a particular draw, x is proportional to
(source: wikimedia.org)
.
In general, the approach is to draw from a uniform random distribution and then pick the value of the desired distribution's cumulative distribution function (CDF) at that drawn location. In the case of a Normal Gaussian, draw a random number, x from a uniform distribution (this is what standard random number generators should give) and then choose as the random, Gaussian distributed value. For your case, the CDF you describe is a piece-wise continuous stair-step function which could be implemented using any of the many (correct) answers you have already received.
Of course, this is all trivia. What you should be doing is using a library that already handles this for you. Statistics and random number generation are not trivial and there's no need to re-invent the wheel. See Neil's answer (and check out the Boost random number library).
Why don't you just use a regular random number generator that return number between 0.0 and 1.0, and wrap it with another function that returns a number according to your requirements?
like
double biased (double seed) {
if (seed >= 0.0 && seed <0.2) return 1;
else if ...
}
Throw a random real number x in [0,1], if 0< x<0.2 return 1, if 0.2<x <0.3 return 2, etc.
See here for the general problem.
Kenny gave an appropriate answer tailored to your particular frequency distribution.
The more general answer works with a CDF - Cumulative Distribution Function - for the data, and uses a uniform random number to pick a value within the distribution.
I am doing to do the same thing and I found this:
http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/
Seems good enough for the purpose you stated.
#include <boost/random/discrete_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>
#include <iostream>
int main()
{
unsigned int seed = 42;
boost::mt19937 generator(seed);
// return 0 with probability 10%
// 1 40%
// 2 50%
boost::random::discrete_distribution<int> custom_dist{1,4,5};
boost::variate_generator<boost::mt19937&,
boost::random::discrete_distribution<int> > rndn(generator, custom_dist);
for (unsigned int i = 0; i<10000; i++) {
std::cout << rndn() << std::endl;
}
return 0;
}
And here is a plot of the result:
I was looking for something like this for TypeScript, but only found this question for C.
So here is a biased random number generator in TypeScript I came up with, in case anybody needs something like this in TypeScript. I am sure you can translate it to C somehow.
export async function weightedRandomItem<T>(list: { weight: number; item: T }[]): Promise<T> {
const weightSum = sumBy(list, (item) => item.weight)
const randomIndex = await randomIntegerBetween(1, weightSum)
let currentIndex = 1
for (const listItem of list) {
if (randomIndex >= currentIndex && randomIndex < currentIndex + listItem.weight) {
return listItem.item
}
currentIndex += listItem.weight
}
throw new Error("No item selected. Impossible.")
}
where randomIntegerBetween(minInclusive: number, maxInclusive: number) returns a random integer from the specified range (min and max inclusive) from the RNG of your choice.
sumBy() is the lodash function in this case, and it should be self-explanatory.
As input you could pass in something like:
[{
weight: 10,
item: 1,
},
{
weight: 50,
item: 2,
},
{
weight: 30,
item: 3,
},
{
weight: 10,
item: 4,
}]
Then, the result would most probably be 2.