This is a follow up question on an answer on this page:
How to generate random double numbers with high precision in C++?
#include <iostream>
#include <random>
#include <iomanip>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<> dist(1, 10);
for( int i = 0 ; i < 10; ++i )
{
std::cout << std::fixed << std::setprecision(10) << dist(e2) << std::endl ;
}
return 0 ;
}
The answer works fine but I had a hard time to realize how to put the output of this code in a double variable instead of printing it to stdout. Can anyone help with this?
Thanks.
You're getting confused between actual precision and displayed precision - try this:
#include <iostream>
#include <random>
#include <iomanip>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<> dist(1, 10);
double v = dist(e2); // get a random double at full precision
std::cout << std::fixed << std::setprecision(10) << v << std::endl;
// display random double with 10 digits of precision
return 0;
}
Related
See the following program for g++.
#define seed1 0
#include <iostream>
#include <random>
int main()
{
double mean = 0.0;
double stddev = 1.0;
std::mt19937 generator1 (seed1);
std::normal_distribution<double> normal(mean, stddev);
std::cerr << "Normal: " << normal(generator1) << std::endl;
}
I want to get the state of generator1 (as a seed) and remove generator1 for later
instantiate again the distribution with the new seed and go on in the place I left I want to put this code in a function and call it to generate Gaussian points in the start state I want. And at the end of the function save the state as a seed.
save the state as a seed
That will never happen, the state of a generator is much more than its seed.
However, generators (and distributions, which you ignored in your question) do provide functionality to store and retrieve their state through the << / >> operators respectively on streams:
stream << generator1 << normal;
And later:
mt19937 generator;
stream >> generator;
normal_distribution<double> distribution;
stream >> distribution;
Let me also add, that generators and distributions are also constructible and copyable from itself, if there is a need to reuse it later.
#define seed1 0
#include <iostream>
#include <random>
int main()
{
double mean = 0.0;
double stddev = 1.0;
std::mt19937 generator1 (seed1);
std::normal_distribution<double> normal(mean, stddev);
std::cerr << "Normal: " << normal(generator1) << std::endl;
std::mt19937 generator2 = generator1;
std::normal_distribution<double> normal2 = normal;
std::cerr << "Normal: " << normal(generator1) << std::endl;
std::cerr << "Normal2: " << normal2(generator2) << std::endl;
// I want to get the state of generator1 (as a seed) and remove generator1 for later
//instantiate again the distribution with the new seed and go on in the place I left
// I want to put this code in a function and call it to generate Gaussian points in
// the start state I want. And at the end of the function save the state as a seed.
}
So last lines print the same result, as states were initialized to equal values.
There is one way you could try. This involves saving the original seed, and counting how many times the generator is called. To restore the state, seed with the original seed and then call std::mt19937::discard()
Example:
#define seed1 0
#include <cassert>
#include <iostream>
#include <random>
// spoof a generator that counts the number of calls
class my_mt19937 : public std::mt19937 {
public:
result_type operator()() {
++call_count_;
return std::mt19937::operator()();
}
void seed(result_type value = default_seed) {
original_seed_ = value;
std::mt19937::seed(value);
}
void discard(unsigned long long z) {
call_count_ += z;
std::mt19937::discard(z);
}
unsigned long long call_count() const noexcept { return call_count_; }
result_type original_seed() const noexcept { return original_seed_; }
private:
result_type original_seed_ = default_seed;
unsigned long long call_count_ = 0;
};
int main() {
double mean = 0.0;
double stddev = 1.0;
my_mt19937 gen1;
gen1.seed(seed1);
const size_t N = 10'000;
for (size_t i = 0; i < N; ++i) {
my_mt19937 gen2;
gen2.seed(gen1.original_seed());
gen2.discard(gen1.call_count());
if (gen2() != gen1()) {
std::cout << "failed for i = " << i << "\n";
return 1;
}
}
// this extneds to distribution objects that
// use the generators
std::normal_distribution<double> normal1;
std::normal_distribution<double> normal2;
for (size_t i = 0; i < N; ++i) {
my_mt19937 gen2;
gen2.seed(gen1.original_seed());
gen2.discard(gen1.call_count());
if (normal1(gen1) != normal2(gen2)) {
std::cout << "failed for i = " << i << "\n";
return 1;
}
}
std::cout << "Success! Tested " << N << " values\n";
return 0;
}
You can play further with the code on godbolt: https://godbolt.org/z/8j9onsezs
I am trying to generate a random number between 0 and 2 (inclusive) for a C++ program:
#include <iostream>
#include <string>
#include <cstdlib>
#include <random>
using namespace std;
int generateRowMovement(){
//http://www.cplusplus.com/reference/random/uniform_int_distribution/
default_random_engine generator;
uniform_int_distribution<int> distribution(0,2);
int row = distribution(generator);
return row;
}
int main(){
int row = generateRowMovement();
cout << row << endl;
int row2 = generateRowMovement();
cout << row2 << endl;
int row3 = generateRowMovement();
cout << row3 << endl;
return 0;
}
All 3 results are:
0
0
0
I have been testing this for 30 minute and it is always zero. I have tried following this link and this SO post (which posts link back to), but none of their solution is fix this problem. How can I generate 0, 1, and 2?
There are two issues with the code you posted that keeps it from working how you intend it to. The first is that generator is never given a seed, or as is commonly shown online, a random_device, ie
random_device rd;
default_random_engine generator(rd());
The second is that every time you call the function, you're creating a new random engine, and a new distribution. It would be better to create a random device, give it to to the engine only once, and then let your function return the values based on those.
#include <iostream>
#include <string>
#include <cstdlib>
#include <random>
using namespace std;
random_device rd;
default_random_engine generator(rd());
uniform_int_distribution<int> distribution(0,2);
int generateRowMovement(){
return distribution(generator);
}
int main(){
int row = generateRowMovement();
cout << row << endl;
int row2 = generateRowMovement();
cout << row2 << endl;
int row3 = generateRowMovement();
cout << row3 << endl;
return 0;
}
I need a series of normally distributed random numbers, with different mean and variance, I know how to create one series with a particular mean and variance but can I have like an array of generators?
like for 1 series we have
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd;
mt19937 gen(rd());
normal_distribution<double> d(0.0, 1.0);
for (int i = 0; i < 5000; i++)
cout << " " << d(gen) << "\n";
return 0;
}
and this gives me a series of normally distributed random numbers, and i know i can create another d with another mean and variance for another series but is there any way to have a lot of such normal_distribution d together in an array so that i can choose a particular generator by simply choosing an element in the array.
I have tried a version where
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd;
mt19937 gen(rd());
normal_distribution<double> d(0.0, 1.0),d2(0.0,1.0);
normal_distribution<double> D[]={d,d2};
for (int i = 0; i < 5000; i++)
cout << " " << D[0](gen) << "\n";
system("pause");
return 0;
}
but I want to initialize it directly with the array like D0 some thing like that so that i can put it in a loop
Sure you can
#include <iostream>
#include <vector>
#include <random>
int main() {
std::vector<std::normal_distribution<double>> D{
std::normal_distribution<double>{0.0, 1.0 },
std::normal_distribution<double>{0.0, 2.0 } };
std::random_device rd;
std::mt19937 gen(rd());
std::cout << D[0](gen) << "\n";
std::cout << D[1](gen) << "\n";
return 0;
}
As you know C++ provide a functions for random numbers and we can also create and initialize array as given below. I hope it will helpful if not comment below.
const int nrolls=10000; // number of experiments
const int nstars=100; // maximum number of stars to distribute
std::default_random_engine generator;
std::normal_distribution<double> distribution(5.0,2.0);
int p[10]={};
for (int i=0; i<nrolls; ++i) {
double number = distribution(generator);
if ((number>=0.0)&&(number<10.0)) ++p[int(number)];
}
std::cout << "normal_distribution (5.0,2.0):" << std::endl;
for (int i=0; i<10; ++i) {
std::cout << i << "-" << (i+1) << ": ";
std::cout << std::string(p[i]*nstars/nrolls,'*') << std::endl;
}
This question has been asked before (stackoverflow) but the (accepted) answer is not satisfactory.
The following example saves and loads the state but depending on the number of generated values it works or it doesn't:
#include <fstream>
#include <iostream>
#include <random>
#include <cassert>
int main()
{
const int preN = 4;
const int middleN = 0;
// initialize randGen
std::mt19937 randGen1;
std::normal_distribution<double> distribution1;
// print some initial random numbers
for (int i=0;i<preN;++i)
std::cout << distribution1(randGen1)<<" ";
// save state
std::cout << std::endl << "Saving...\n";
{
std::ofstream fout("seed.dat");
fout << randGen1;
}
// maybe advance randGen1
for (int i=0;i<middleN;++i)
std::cout << distribution1(randGen1)<<" ";
// load saved state into randGen2
std::cout << std::endl << "Loading...\n";
std::ifstream fin("seed.dat");
std::mt19937 randGen2;
fin >> randGen2;
std::normal_distribution<double> distribution2;
// are both randGen equal?
assert(randGen1 == randGen2);
// print numbers from both generators
std::cout << "Generator1\tGenerator2\n";
std::cout << distribution1(randGen1) << "\t"
<< distribution2(randGen2) << "\n";
return 0;
}
With these parameters it works like expected. However, if I set preN=3 the output looks like:
0.13453 -0.146382 0.46065
Saving...
Loading...
Generator1 Generator2
-1.87138 0.163712
Why did the assert not apply? Now I set preN=3 and middleN=1 and the output is
0.13453 -0.146382 0.46065
Saving...
-1.87138
Loading...
Generator1 Generator2
0.163712 0.163712
If I set middleN to anything larger than 1 the assert applies.
Can anyone explain what is going on? What am I doing wrong or not understanding?
Tested with GCC5.4.0 and CLANG3.8.0 on Linux
The problem is not your random number generator's state. The problem is your distribution's state. Yes, distributions can have state too.
You can get the same values by resetting the normal distribution's state with reset. Alternatively, you can preserve and reconstitute the distribution's state too, using << and >>.
Thanks to the answer from Nicol Bolas above, I can add the corrected code below:
#include <fstream>
#include <iostream>
#include <random>
#include <cassert>
int main()
{
const int preN = 7;
const int middleN = 0;
// initialize another randGen
std::mt19937 randGen1;
std::normal_distribution<double> distribution1;
// print some initial random numbers
for (int i=0;i<preN;++i)
std::cout << distribution1(randGen1)<<" ";
// save state
std::cout << std::endl << "Saving...\n";
{
std::ofstream fout("seed.dat");
fout << randGen1;
fout.close();
std::ofstream fout2("distribution.dat");
fout2 << distribution1;
fout2.close();
}
// maybe advance randGen
for (int i=0;i<middleN;++i)
std::cout << distribution1(randGen1)<<" ";
// load saved state into randGen2
std::cout << std::endl << "Loading...\n";
std::mt19937 randGen2;
std::normal_distribution<double> distribution2;
{
std::ifstream fin("seed.dat");
fin >> randGen2;
fin.close();
std::ifstream fin2("distribution.dat");
fin2 >> distribution2;
fin2.close();
}
// are both randGen equal?
assert(randGen1 == randGen2);
assert(distribution1 == distribution2);
// print numbers from both generators
std::cout << "Generator1\tGenerator2\n";
std::cout << distribution1(randGen1) << "\t"
<< distribution2(randGen2) << "\n";
return 0;
}
Here is how one can save and restore seed forrandom numbers of double float precision. It should be similar for integers - use jrand48 instead of erand48.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned short savedseed[3];
unsigned short currentseed[3];
double x;
/*-- initialize ramdom seed to whatever --*/
currentseed[0]= 23;
currentseed[1]= 45;
currentseed[2]= 67;
printf("\n");
/*-- generate three random numbers --*/
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
printf("\n");
/*-- save seed --*/
memcpy(savedseed, currentseed, 3*sizeof(unsigned short));
/*-- generate next three random numbers --*/
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
printf("\n", x);
/*-- restore seed --*/
memcpy(currentseed, savedseed, 3*sizeof(unsigned short));
/*-- generate the same three random numbers again --*/
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
x = erand48(currentseed); printf("%g\n", x);
printf("\n");
}
This question already has answers here:
c++ integer->std::string conversion. Simple function?
(3 answers)
Closed 9 years ago.
My code:
#include <iostream>
#include <random>
void main()
{
std::random_device rd;
std::cout << "Random value: " << rd() << std::endl;
system("pause");
}
How do i get the result rd(), and convert it to std::string?
Since you are asking how to convert the result of std::random_device to a string, and std::random_device returns an unsigned int. C++11 provides std::to_string, can be used to convert numbers to strings. See here.
#include <iostream>
#include <random>
#include <string>
int main()
{
std::random_device rd;
std::string str = std::to_string(rd());
std::cout << str << std::endl;
return 0;
}
Here's an example I found on http://en.academic.ru/dic.nsf/enwiki/11574016
#include <random>
#include <functional>
std::uniform_int_distribution<int> distribution(0, 99);
std::mt19937 engine; // Mersenne twister MT19937
auto generator = std::bind(distribution, engine);
int random = generator(); // Generate a uniform integral variate between 0 and 99.
int random2 = distribution(engine); // Generate another sample directly using the distribution and the engine objects.
I haven't worked with it before, but this might help you get started.
std::stringstream is one way to convert a number to a string, the code below shows various engines and distributions possible. It defaults to Mersenne Twister for the engine and the normal distribution. This is good reference for the options available:
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <sstream>
int main()
{
std::random_device rd;
//
// Engines
//
std::mt19937 e2(rd());
//std::knuth_b e2(rd());
//std::default_random_engine e2(rd()) ;
//
// Distribtuions
//
std::normal_distribution<> dist(2, 2);
//std::student_t_distribution<> dist(5);
//std::poisson_distribution<> dist(2);
//std::extreme_value_distribution<> dist(0,2);
std::stringstream s1 ;
s1 << dist(e2) ;
std::string str1 = s1.str();
std::cout << str1 << std::endl ;
}
another method to convert to a string would be to use std::to_string:
str1 = std::to_string( dist(e2) ) ;
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
unsigned int maxValue = 50;
std::cout << "Random value: " << rand()%maxValue; //random between 0-50
return 0;
}