I need to generate a random number between 1 and n where n is unsigned int.
If n were int I would simply write 1 + rand()% n. But unfortunately n is unsigned int. What do you suggest?
rand() should be avoided whenever possible*.
Use http://en.cppreference.com/w/cpp/numeric/random
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 engine(rd());
std::uniform_int_distribution<unsigned> dist(1, 77);
for (int i = 0; i != 5; ++i)
std::cout << dist(engine) << '\n';
}
* Because it shares a global state, gets often implemented as a linear congruential engine which has a few drawbacks and it's range is often only 0-2^16. Also, % n where n is not an exact multiple of the range does not produce an uniform distribution.
Edit: This might seem like overkill, but technically one would want something like this, since mt19937 needs a bit of "warm up":
std::mt19937 create_seeded_rng()
{
std::random_device rd;
std::array<std::mt19937::result_type, std::mt19937::state_size> seed_data;
std::generate(seed_data.begin(), seed_data.end(), std::ref(rd));
std::seed_seq seq(seed_data.begin(), seed_data.end());
return std::mt19937(seq);
}
int main()
{
std::mt19937 rng = create_seeded_rng();
std::uniform_int_distribution<int> dist(0, 100);
for (unsigned i = 0; i != 100; ++i)
std::cout << dist(rng) << '\n';
}
Related
As mentioned in the title I want to generate a random floating-point number between -10 and 10 but I want to make it so that it can't generate a number between -1.99 and 1.99.
My code for randomly generating numbers:
std::random_device random;
std::mt19937 gen(random());
std::uniform_real_distribution<float> dis(-10.0f, 10.0f);
for (int n = 0; n < 10; ++n)
{
std::cout << dis(gen); << std::endl;
}
you can use std::piecewise_constant_distribution:
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
// 50% of the time, generate a random number between -10.0f and -1.99f
// 50% of the time, generate a random number between 1.99f and 10.0f
std::vector<float> i{-10.0f, -1.99f, 1.99, 10.0f};
std::vector<float> w{1, 0, 1};
std::piecewise_constant_distribution<float> dis(i.begin(), i.end(), w.begin());
for (int n = 0; n < 10; ++n)
std::cout << dis(gen) << std::endl;
}
Demo.
I want to generate a new random every time in a while loop until the loop breaks when it meets the condition in the while loop like 10 random numbers.
you could find something on https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
int main()
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
//Use dis to transform the random unsigned int generated by gen into an int in [1, 6]
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
where the for loop can obviously be replaced by a while
This doesn't work:
for (int p = 0; p < 10; p++) {
random_device rd;
mt19937 gen(rd);
uniform_real_distribution<int> dis(0, INT_MAX);
printf("%i\n", dis(gen));
}
Any advice would be appreciated.
You have few mistakes in your code.
You should move creation of random_device and seeding mt19937 outside the for loop. I'll also suggest the same for uniform_real_distribution<int>
mt19937 takes in the constructor value of seed not random_device so you have to call it to get seed(rd())
You should use uniform_int_distribution<int> if you are generating integers
If your intention is to generate number to 0x7FFFFFFF you should put this number explicitly but if you want to get numbers to max int value i'll suggest using more C++ style std::numeric_limits<int>::max()
Here is working example:
#include <cstdio>
#include <random>
#include <limits>
using namespace std;
int main(){
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(0, std::numeric_limits<int>::max());
for (int p = 0; p < 10; p++) {
printf("%i\n", dis(gen));
}
return 0;
}
I've a function to generate random characters from a set of alphabets. This function would be called multiple times and thus I'm trying to make it use same set of variables, ie have same seed so that strings don't repeat as long as possible.
#include <iostream>
#include <random>
#include <string>
std::string generateRandomChar(const unsigned int _len)
{
std::string result;
result.reserve(_len);
static constexpr char alphanum[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 61);
for (int i = 0; i < _len;
result += (alphanum[dis(gen)]);
}
return result;
}
int main(){
for(int i = 0; i < 10; ++i){
std::cout << generateRandomChar(10) << std::endl;
}
}
Unfortunately I don't have any expertise with c++11 functions and I was only using srand and friends earlier, so I might be making lots of mistakes here. Currently it works and generates tons of strings without repeating, but I'm sure I could make either of -
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 61);
static variable too, so that it isn't calculated each time the function is called because that would be waste right?
So which one should be static here? Are there any mistakes/improvements that you see here?
Thankyou :D
edit - here's an ideone link - http://ideone.com/e7ssXo
So which one should be static here?
Either std::mt19937 gen or none of them.
std::random_device generates uniformly-distributed random integers using non-deterministic entropy source, if available. Your code uses std::random_device output as a seed for std::mt19937 pseudo-random generator. So you are very likely to have good, non-deterministic seeds for std::mt19937 if you run on a PC, and thus there is no need to make any of them static. I suppose that std::random_device is implemented as a pure-procedural PRNG only on low-end controllers.
On the other hand, one-time seeding is more idiomatic, so you may declare std::mt19937 as static. std::mt19937 itself implements a high-quality PRNG algorithm with 19937 bits of state, so it's period probably exceeds the Universe lifetime (or at least the stelliferous era), if the generator is running on a modern PC.
There is no need to make std::uniform_int_distribution static, as it's only a wrapper which modifies actual generator's output according to desired distribution properties. So it's up to you to decide whether make it static or not.
To allow unit test, I suggest to move the generator outside of the function, something like
std::string generateRandomChar(const unsigned int len, std::mt19937& gen)
{
std::string result;
result.reserve(len);
static constexpr char alphanum[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::uniform_int_distribution<> dis(0, 61);
for (int i = 0; i < len; ++i) {
result += (alphanum[dis(gen)]);
}
return result;
}
int main() {
std::random_device rd;
std::mt19937 gen(rd());
for (int i = 0; i < 10; ++i) {
std::cout << generateRandomChar(10, gen) << std::endl;
}
}
or create a class
class RandomCharGenerator
{
public:
RandomCharGenerator() : RandomCharGenerator(std::random_device{}()) {}
template <typename T>
RandomCharGenerator(T&& seed) : gen(std::forward<T>(seed)) {}
std::string operator() (const unsigned int len)
{
std::string result;
result.reserve(len);
for (int i = 0; i < len; ++i) {
result += (alphanum[dis(gen)]);
}
return result;
}
private:
std::mt19937 gen;
std::uniform_int_distribution<> dis{0, 61};
static constexpr char alphanum[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
};
int main() {
RandomCharGenerator charGenerator{};
for (int i = 0; i < 10; ++i) {
std::cout << charGenerator(10) << std::endl;
}
}
You can eventually templated things to allow other rand generator.
You can make your random_device and mt19937 static. Currently you are constructing one everytime the function is called (IIRC, mt19937 is expensive to construct. Someone corect me). Also, your uniform_int_distribution can be moved out of the loop. This question is better suited for codereview as it already works and you are looking for improvements.
TL;DR: You can make all of them static.
I just played around with Eigen a bit and noticed that MatrixXf::Random(3,3) always returns the same matrices, first one is always this for example:
0.680375 0.59688 -0.329554
-0.211234 0.823295 0.536459
0.566198 -0.604897 -0.444451
Is that intended behaviour or am i just overseeing something really simple? (My experience with mathematic libraries is close to zero)
Code i used:
for(int i = 0; i < 5; i++) {
MatrixXf A = MatrixXf::Random(3, 3);
cout << A <<endl;
}
Instead of srand you can also use a nullary expression together with modern C++11 random number generation:
//see https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
std::random_device rd;
std::mt19937 gen(rd()); //here you could set the seed, but std::random_device already does that
std::uniform_real_distribution<float> dis(-1.0, 1.0);
Eigen::MatrixXf A = Eigen::MatrixXf::NullaryExpr(3,3,[&](){return dis(gen);});
This also allows to use more complex distributions such as a normal distribution.
Yes, that's the intended behaviour. Matrix::Random uses the random number generator of the standard library, so you can initialize the random number sequence with srand(unsigned int seed), for instance:
srand((unsigned int) time(0));
#orian:
std::srand(unsigned seed) is not an Eigen function. The complete code should work like that:
std::srand((unsigned int) time(0));
for(int i = 0; i < 5; i++) {
MatrixXf A = MatrixXf::Random(3, 3);
cout << A <<endl;
}
How about this way?
#include<iostream>
#include<random>
#include <Eigen/Dense>
int main(){
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dis(0, 1);
Eigen::MatrixXf m = Eigen::MatrixXf::Zero(10,10).unaryExpr([&](float dummy){return dis(gen);});
cout<<"Uniform random matrix:\n"<<m<<endl;
cout<<"Mean: "<<m.mean()<<endl;
return 0;
}