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.
Related
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.
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.
I was wondering if there was a way to have a random number between A an b and where if a number meets a certain requirement it is more likely to appear than all the other numbers between A and B, for example: Lower numbers are more likely to appear so if A = 1 and B = 10 then 1 would be the likeliest and 10 would be the unlikeliest.
All help is appreciated :) (sorry for bad English/grammar/question)
C++11 (which you should absolutely be using by now) added the <random> header to the C++ standard library. This header provides much higher quality random number generators to C++. Using srand() and rand() has never been a very good idea because there's no guarantee of quality, but now it's truly inexcusable.
In your example, it sounds like you want what would probably be called a 'discrete triangular distribution': the probability mass function looks like a triangle. The easiest (but perhaps not the most efficient) way to implement this in C++ would be the discrete distribution included in <random>:
auto discrete_triangular_distribution(int max) {
std::vector<int> weights(max);
std::iota(weights.begin(), weights.end(), 0);
std::discrete_distribution<> dist(weights.begin(), weights.end());
return dist;
}
int main() {
std::random_device rd;
std::mt19937 gen(rd());
auto&& dist = discrete_triangular_distribution(10);
std::map<int, int> counts;
for (int i = 0; i < 10000; i++)
++counts[dist(gen)];
for (auto count: counts)
std::cout << count.first << " generated ";
std::cout << count.second << " times.\n";
}
which for me gives the following output:
1 generated 233 times.
2 generated 425 times.
3 generated 677 times.
4 generated 854 times.
5 generated 1130 times.
6 generated 1334 times.
7 generated 1565 times.
8 generated 1804 times.
9 generated 1978 times.
Things more complex than this would be better served with either using one of the existing distributions (I have been told that all commonly used statistical distributions are included) or by writing your own distribution, which isn't too hard: it just has to be an object with a function call operator that takes a random bit generator and uses those bits to produce (in this case) random numbers. But you could create one that made random strings, or any arbitrary random objects, perhaps for testing purposes).
Your question doesn't specify which distribution to use. One option (of many) is to use the (negative) exponential distribution. This distribution is parameterized by a parameter λ. For each value of λ, the maximum result is unbounded (which needs to be handled in order to return results only in the range specified)
(from Wikipedia, By Skbkekas, CC BY 3.0)
so any λ could theoretically work; however, the properties of the CDF
(from Wikipedia, By Skbkekas, CC BY 3.0)
imply that it pays to choose something in the order of 1 / (to - from + 1).
The following class works like a standard library distribution. Internally, it generates numbers in a loop, until a result in [from, to] is obtained.
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
class bounded_discrete_exponential_dist {
public:
explicit bounded_discrete_exponential_dist(std::size_t from, std::size_t to) :
m_from{from}, m_to{to}, m_d{0.5 / (to - from + 1)} {}
explicit bounded_discrete_exponential_dist(std::size_t from, std::size_t to, double factor) :
m_from{from}, m_to{to}, m_d{factor} {}
template<class Gen>
std::size_t operator()(Gen &gen) {
while(true) {
const auto r = m_from + static_cast<std::size_t>(m_d(gen));
if(r <= m_to)
return r;
}
}
private:
std::size_t m_from, m_to;
std::exponential_distribution<> m_d;
};
Here is an example of using it:
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
bounded_discrete_exponential_dist d{1, 10};
std::vector<std::size_t> hist(10, 0);
for(std::size_t i = 0; i < 99999; ++i)
++hist[d(gen) - 1];
for(auto h: hist)
std::cout << std::string(static_cast<std::size_t>(80 * h / 99999.), '+') << std::endl;
}
When run, it outputs a histogram like this:
$ ./a.out
++++++++++
+++++++++
+++++++++
++++++++
+++++++
+++++++
+++++++
+++++++
++++++
++++++
Your basic random number generator should produce a high-quality, uniform random numbers on 0 to 1 - epsilon. You then transform it to get the distribution you want. The simplest transform is of course (int) ( p * N) in the common case of needing an integer on 0 to N -1.
But there are many many other transforms you can try. Take the square root, for example, to bias it to 1.0, then 1 - p to set the bias towards zero. Or you can look up the Poisson distribution, which might be what you are after. You can also use a half-Gaussian distribution (statistical bell curve with the zero entries cut off, and presumably also the extreme tail of the distribution as it goes out of range).
There can be no right answer. Try various things, plot out ten thousand or so values, and pick the one that gives results you like.
You can make an array of values, the more likely value has more indexes and then choose a random index.
example:
int random[55];
int result;
int index = 0;
for (int i = 1 ; i <= 10 ; ++i)
for (int j = i ; j <= 10 ; ++j)
random[index++] = i;
result = random[rand() % 55];
Also, you can try to get random number twice, first time you choose the max number then you choose your random number:
int max= rand() % 10 + 1; // This is your max value
int random = rand() % max + 1; // This is you result
Both ways will make 1 more likely than 2 , 2 more likely than 3 ... 9 more likely than 10.
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
I would like to generate a random number between 0 and 3 and I have the following in my code:
int random = rand() % 4;
This works fine but I would like it to generate 1, 2, and 3 most of the time and 0 only occasionally.
What is the best way to go about this? What are the names of common algorithms to address this problem?
Here's one way. Suppose you want 0, 1, 2, 3 to have a distribution of 5%, 20%, 30%, 45%.
You could do it like this:
double val = (double)rand() / RAND_MAX;
int random;
if (val < 0.05) // 5%
random = 0;
else if (val < 0.25) // 5% + 20%
random = 1;
else if (val < 0.55) // 5% + 20% + 30%
random = 2;
else
random = 3;
Of course it doesn't have to be done with floating-point. I just did it this way since it's more intuitive.
You can use the discrete_distribution class from the random library.
#include <iostream>
#include <random>
#include <ctime>
int main()
{
std::discrete_distribution<> dist({ 1.0, 4.0, 4.0, 4.0 });
std::mt19937 eng(std::time(0));
for (int i=0; i<100; ++i)
std::cout << dist(eng);
}
Demo: http://ideone.com/z8bq4
If you can't use C++11, these classes also exist in boost.
You didn't give exact proportions, but suppose you want 1, 2, and 3 to each occur 32% of the time, and 0 to occur the other 4%. Then you could write:
int random = rand() % 25;
if(random > 0)
random = random % 3 + 1;
(Obviously you'd need to adjust that for different proportions. And the above is just one approach; many similar approaches could work.)
how many numbers have you tested this on? if it is actually true you can instead generate a range from say 0->3999 using a = rand()%4000 and use int = a/1000 this should remove the weight of the apparently under produced zero.
I would just map more values to 1,2,3 from a larger set. For example: 9 and map 1,2,3 => 1, 3,4,5=>2, 6,7,8=>3 and 0 for zero. There are other ways, but I am working within your question
Just code exactly what you want:
int myrand(void)
{
const int percentZero = 10;
if ((rand()%100) < percentZero) return 0;
return 1 + (rand() % 3);
}
You can change the percentage of time zero is returned to whatever you want.
You need to find a probability distribution that works for your case. Since you're only talking about the numbers 0-3 this is quite easy, you could either call rand() again if the first result is a 0, or you could use weights:
int random = rand() % 16;
if(random > 10)
{
random = 3;
}
else if(random > 5)
{
random = 2;
}
else if(random > 0)
{
random = 1;
}
This isn't a particularly elegant, but hopefully it shows you how you can create a custom distribution to fit your needs.