Function not updating internal state of mt19937 [duplicate] - c++

This question already has answers here:
C++ function not updating variables
(1 answer)
c++ trying to change local variable outside of function?
(1 answer)
Closed 7 months ago.
I have a function that generates and writes random integers:
void randint(int min, int max, int times,std::mt19937 rng){
std::uniform_int_distribution<int> dist(min, max);
for (int i=0;i<times;i++){
std::cout<<dist(rng)<<' ';
}
}
When this function is called, generates numbers from the mt19937 object. However, when returning from the function, the mt19937 object's internal state is not updated.
This can be seen by running this code below.
int main(){
std::mt19937 gen(2845);
std::uniform_int_distribution<int> spread(1,100);
randint(1,100,5,gen);
std::cout<<"| ";
for (int i=0;i<5;i++){
std::cout<<spread(gen)<<' ';
}
Actual Output:
88 93 79 43 92 | 88 93 79 43 92
Expected output:
88 93 79 43 92 | 97 71 34 32 70
Is there any way for the internal state to be continuously updated even when passed through the function?

You are passing the object by value (i.e. you are copying the object when you call the function). Use a reference
void randint(int min, int max, int times,std::mt19937& rng){

Related

C++ rand() always giving same TWO values... and then working perfectly [duplicate]

This question already has answers here:
Rand() % 14 only generates the values 6 or 13
(3 answers)
Closed 5 months ago.
First, I know the basic principle of planting a time seed, and my program's outputs are partially random. But this baffles me.
On subsequent executions of the program, the seven randomly generated values may look like this:
14 14 47 70 84 2 24
14 28 42 52 31 10 12
63 25 4 50 20 27 56
63 19 55 44 65 60 52
14 16 17 40 54 77 4
63 6 79 36 51 85 39
The rest of the values appear random, but the first value is always either 14 or 63. Why is this happening, and how can I make it completely random?
The code is supposed to draw a random Scrabble letter without replacement, with a cout statement added for debugging purposes.
#include <iostream>
using namespace std;
int main()
{
string bag = "AAAAAAAAABBCCDDDDEEEEEEEEEEEEFFGGGHHIIIIIIIIIJKLLLLMMNNNNNNOOOOOOOOPPQRRRRRRSSSSTTTTTTUUUUVVWWXYYZ";
srand(time(0));
for (int a = 0; a < 7; a++)
{
int i = rand()%bag.size();
cout << i << ' ';
bag.erase(i,1);
}
cout << endl;
return 0;
}
Compiled in MacOS Catalina 10.15 terminal
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
As has been explained in comments, it looks like your compiler's C runtime library has a bad rand function.
But you're not using C, you're using C++! Starting at C++11, you have all sorts of random-number generation facilities available in the C++ standard library.
#include <iostream>
#include <string>
#include <random>
int main()
{
std::random_device eng; // or any other type of engine
using dist_params = typename std::uniform_int_distribution<int>::param_type;
int max = 99;
std::uniform_int_distribution<int> dist (0, max);
for (int a = 0; a < 7; a++)
{
int i = dist(eng);
std::cout << i << ' ';
dist.param(dist_params{0, max});
}
std::cout << '\n';
return 0;
}
Or, what I expect you were really going for:
#include <iostream>
#include <string>
#include <random>
#include <time.h>
int main()
{
std::string bag0 = "AAAAAAAAABBCCDDDDEEEEEEEEEEEEFFGGGHHIIIIIIIIIJKLLLLMMNNNNNNOOOOOOOOPPQRRRRRRSSSSTTTTTTUUUUVVWWXYYZ";
std::random_device eng;
time_t t;
using dist_params = typename std::uniform_int_distribution<size_t>::param_type;
std::uniform_int_distribution<size_t> dist;
for (auto j = 0; j<100; ++j)
{
auto bag = bag0;
for (int a = 0; a < 7; a++)
{
dist.param(dist_params{0, (bag.length())-1});
int i = dist(eng);
std::cout << bag[i] << ' ';
bag.erase(i, 1);
}
std::cout << '\n';
}
return 0;
}
The only caveat is that random_device may not produce random numbers on your platform.
rand() or std::rand() never generates true random number. It generates pseudo-random numbers. This is because computers are unable to generate truly random numbers itself, it requires assistance. Let's say you pressed a key exactly 2.054 seconds after the previous keypress. This is truly a random number. Computers use this data to generate truly random numbers. rand() or std::rand() generates a pseudo-random number, so needs to be seeded (with srand() or std::srand()). If the number you used to seed isn't random, the output wouldn't be random too. Moreover, you are using time() (or std::time()) which returns an int holding the number of seconds passed since epoch. So if you execute the program multiple times too rapidly, the seed would be the same and the output too. It also seems that your standard library a bad rand() or std::rand() function.
Example:
Output of the program (compiled from your code) executed 10 times rapidly (environment: Ubuntu, bash):
$ for i in {0..9} ; do ./a.out ; done
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
50 11 3 60 36 17 42
What to do?
I can suggest you use another time function to seed, which outputs time in milliseconds (or even nanoseconds) or get your own random number generator. See this article to know how pseudo-random number generators work. This will also help you to build your own as it seems that your standard library gives a bad rand() or std::rand() function.

How can I generate a random number from 1 - 39 without making a number overlap? [duplicate]

This question already has answers here:
Unique (non-repeating) random numbers in O(1)?
(22 answers)
Closed 8 years ago.
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void randnum()
{
int random;
srand((unsigned int)time(0));
for(int i=1;i<=5;i++)
{
random=(rand()%39)+1;
cout<<random<<endl;
}
}
int main()
{
cout<<"Five random number is here"<<endl;
randnum();
system ("PAUSE");
return 0;
}
I am randomly doing this to practice C++. I always get confused in setting the range of random generator (is my method correct? from 1-39). Also how can I prevent numbers from overlapping one another? That is, if I am outputting 5 different numbers from 1-39, it can always 5 different numbers like 4,5,2,7,12 instead of 4,5,2,4,12 (4 is used twice here)
Yes, the method of getting a random number between 1 and 39 is correct.
To ensure non-overlapping numbers, two algorithms come to mind:
keep a set of already-served numbers and skip when they are picked a second time, or
create a list of all candidate numbers and randomly reorder them, then serve them in order
The method is correct. To prevent numbers from overlapping one another, for me the best solution would be to create a vector of already generated numbers, and every time you generate a new random number, see if it is already in the vector. If it is, regenerate. If it isn't, then add it to the vector and move on.
Try create a vector containing the numbers 1 -39, shuffle them, and pick the first 5. Then you have 5 non-repeating random numbers.
random_shuffle() function is implemented in the C++ library. Check here:
http://www.cplusplus.com/reference/algorithm/random_shuffle/
random=(rand()%39)+1;
This could lead to a duplicate.
I always get confused in setting the range of random generator (is my method correct from 1-39?)
The number of elements in a range [begin,end] (where the bracket means "inclusive") is:
count = end - begin + 1
If you need one of 0-based count elements, then you perform:
rand() % count
Because the starting element may not be 0, you actually perform the following to get a value in the range:
rand() % count + begin
Also how can I prevent numbers from overlapping one another?
In this case, one of the easier solutions would be to use a vector. Its not as efficient as other answers (like the one #Retired Ninja suggested), but its easier to understand. Something like shown below.
The code below just dumps the result of the shuffle (which is not random because it repeats across runs based on the seed used). It should not be hard for you to adapt it to the first 5 elements (we can't give you all the answers).
ShuffledRange range (1, 39);
...
$ ./tt.exe
29 33 8 37 9 32 38 24 16 14 36 7 10 31 34 39 27 11 6 4 35 1 19 20 18 15 5 12 22
21 3 30 17 25 2 28 23 26 13
If you specify a seed (the default is 0), then you will get a different sequence:
ShuffledRange range (1, 39, 2);
...
$ ./tt.exe
12 20 28 6 7 15 32 17 35 11 18 31 27 4 23 36 25 24 22 1 33 2 37 39 21 9 38 13 5 3
14 10 8 34 16 19 29 26 30
The code below needs C++ 11 because of random_shuffle. Visual Studio 2012 should be fine with C++ 11. I'm not sure about Visual Studio 2010.
GCC will need:
$ g++ -Wall -Wextra -std=c++11 tt.cpp -o tt.exe
And Mac OS X:
$ g++ -Wall -Wextra -std=c++11 -stdlib=libc++ tt.cpp -o tt.exe
class ShuffledRange
{
public:
explicit ShuffledRange(unsigned int low, unsigned int high, int seed=0)
: m_numbers(move(create_numbers(low,high,seed))), m_it(m_numbers.begin()) { }
unsigned int GetCount() const {
return static_cast<unsigned int>(m_numbers.size());
}
bool HasNext() const {
return m_it != m_numbers.end();
}
unsigned int GetNext()
{
if(!HasNext())
throw std::runtime_error("No numbers left");
unsigned int temp = *m_it++;
return temp;
}
protected:
vector<unsigned int> create_numbers(unsigned int low, unsigned int high, int seed)
{
if(high < low)
throw std::runtime_error("Bad range of elements");
vector<unsigned int> temp;
temp.reserve(high - low + 1);
for(unsigned int i = low; i <= high; i++)
temp.push_back(i);
srand(seed);
random_shuffle(temp.begin(), temp.end());
return temp;
}
private:
vector<unsigned int> m_numbers;
vector<unsigned int>::iterator m_it;
};
int main(int argc, char* argv[])
{
ShuffledRange range(1, 39);
while(range.HasNext())
cout << range.GetNext() << " ";
cout << endl;
return 0;
}
A hint....
int main()
{
cout<<"Five random number is here"<<endl;
randnum();
system ("PAUSE");
return 0;
}
If you place a breakpoint (F9) on main's closing brace (i.e., the }), then you won't need the system ("PAUSE");. Visual Studio will break and wait for you. Once you've inspected the values, then press F5 to finish the program.

openMP generate different random numbers with the same seed

I am new to openMP, in my program complex simulations are needed, to repeat the result, the seed is set for each simulation, however, when implementing openMP, different results are produced for each time I run it. so I write a simple example to check the problem as follows,
I also generated different result each time:
#include <iostream>
#include <omp.h>
using namespace std;
int main () {
double A[10];
#pragma omp parallel for
for( int i=0;i<10;i++){
srand(i+1);
int m = rand()%100;
A[i] = m;
}
cout<<"A= \n";
for(int i=0;i<10;i++){
cout<<i<<" "<<A[i]<<" \n";
}
return 0;
}
I run it twice, the results are:
A=
0 86
1 25
2 78
3 1
4 46
5 95
6 77
7 83
8 15
9 8
and
A=
0 15
1 41
2 65
3 1
4 75
5 85
6 95
7 83
8 74
9 8
Thank you very much!
rand() uses static state and is not threadsafe. You'll need to use a different, thread-safe, PRNG. See Thread-safe random number generation for Monte-Carlo integration or Do PRNG need to be thread safe?
This is a bug
A[i] += m;
You're reading the prior value of A[i] which has never been assigned. That's undefined behavior. try
A[i] = m;
Then, note that the random number state might not be threadlocal. Get a better RNG, where you have an explicit state variable instead of accessing shared global state.

Compilation error in CRC encoding program

I wrote the following code for a program that performs CRC encoding. I modeled it on a C program that we were taught in class. It gives some compilation errors that I can't correct. I have mentioned them after the code.
I wrote the following code for a program that performs CRC encoding. I modeled it on a C program that we were taught in class. It gives some compilation errors that I can't correct. I have mentioned them after the code.
1 #include<iostream>
2 #include<string.h>
3
4 using namespace std;
5
6 class crc
7 {
8 char message[128],polynomial[18],checksum[256];
9 public:
10 void xor()
11 {
12 for(int i=1;i<strlen(polynomial);i++)
13 checksum[i]=((checksum[i]==polynomial[i])?'0':'1');
14 }
15 crc() //constructor
16 {
17 cout<<"Enter the message:"<<endl;
18 cin>>message;
19 cout<<"Enter the polynomial";
20 cin>polynomial;
21 }
22 void compute()
23 {
24 int e,i;
25 for(e=0;e<strlen(polynomial);e++)
26 checksum[e]=message[e];
27 do
28 {
29 if(checksum[0]=='0')
30 xor();
31 for(i=0;i<(strlen(polynomial)-1);i++)
32 checksum[i]=checksum[i+1];
33 checksum[i]=message[e++];
34 }while(e<=strlen(message)+strlen(checksum)-1);
35 }
36 void gen_proc() //general processing
37 {
38 int mesg_len=strlen(message);
39 for(int i=mesg_len;i<mesg_len+strlen(polynomial)-1;i++)
40 message[i]='0';
41 message[i]='\0'; //necessary?
42 cout<<"After appending zeroes message is:"<<message;
43 compute();
44 cout<<"Checksum is:"<<checksum;
45 for(int i=mesg_len;i<mesg_len+strlen(polynomial);i++)
46 message[i]=checksum[i-mesg_len];
47 cout<<"Final codeword is:"<<message;
48 }
49 };
50 int main()
51 {
52 crc c1;
53 c1.gen_proc();
54 return 0;
55 }
The compilation errors are:
crc.cpp:10: error: expected unqualified-id before ‘^’ token
crc.cpp: In member function ‘void crc::compute()’:
crc.cpp:30: error: expected primary-expression before ‘^’ token
crc.cpp:30: error: expected primary-expression before ‘)’ token
crc.cpp: In member function ‘void crc::gen_proc()’:
crc.cpp:41: warning: name lookup of ‘i’ changed for ISO ‘for’ scoping
crc.cpp:39: warning: using obsolete binding at ‘i’
I have been checking online for these errors and the only thing I have been seeing is errors caused by incorrect array handling. I have double checked my code but I don't seem to be performing any incorrect array access.
xor is a reserved keyword in C++. You should rename the function to something else.
The compiler isn't actually "seeing" an identifier, but a keyword. If, in your code snippet, you'd replace xor with ^ the obvious syntactic error becomes clear.

I can't figure out what is wrong with this randomizer

I'm new to C++. Only been programming for 2 days so this will probably look messy. The purpose of the program is that you enter a word, and then the program randomizes the placement of the letters in the word.
I have three questions.
Why, if the same string is entered twice, will the same "random" numbers be output?
How can I make sure no random number is picked twice. I already tried an IF statement nested inside the FOR statement but it just made things worse.
What will make this work?
The code:
#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
using namespace std;
int main () {
cout << "Enter word to be randomized: ";
char rstring[30];
char rstring2[30];
cin >> rstring;
strcpy(rstring2, rstring);
int length;
length = strlen(rstring);
int max=length;
int min=0;
int randint;
for (int rdm=0; rdm<length; rdm++) {
randint=rand()%(max-min)+min;
cout << rstring[rdm]; //This is temporary. Just a visualization of what I'm doing.
cout << randint << endl; //Temporary as well.
rstring2[randint]=rstring[rdm];
}
cout << endl << rstring2 << endl;
return 0;
}
If you compile and run this you will notice that the same random numbers are output for the same text. Like "hello" outputs 24330. Why is this random generator generating nonrandom numbers?
You need to seed your random number generator to get different results with each run. Otherwise, (as you have noticed) you will get the same random numbers with each run.
Put this at the start of the program:
srand(time(NULL));
This will seed the random number generator with time - which will likely be different between runs.
Note that you'll also need #include <time.h> to access the time() function.
You're not using a random number generator. You're calling rand(), a pseudo-random number generator, which produces sequences of numbers that share many properties with truly random numbers (e.g. mean, standard deviation, frequency spectrum will all be correct).
To get a different sequence, you have to initialize the seed using srand(). The usual way to do this is:
srand(time(NULL));
Furthermore, a sequence that guarantees the same number cannot be picked twice, is no longer a sequence of i.i.d. (independent identically distributed) random numbers. (the sequence is highly dependent) Most uses of random numbers rely on the i.i.d. property, so the library-provided functions are i.i.d. However, filtering out repeats yourself is not especially hard.
If you don't want to change the cardinality (number of occurrences) of each character in the string, the easiest thing to do is not pick one character after the other, but randomly pick a pair to swap. By only swapping, you change order but not cardinality.
You always get the same random numbers because you don't seed this random number generator. Call srand() before your first call to rand(). Examples: http://www.cplusplus.com/reference/clibrary/cstdlib/srand/
The random number generated by rand() is pseudo-random. C++ rand() documentation says following
rand() Returns a pseudo-random integral number in the range 0 to RAND_MAX.
This number is generated by an algorithm that returns a sequence of apparently non-related numbers each time it is called. This algorithm uses a seed to generate the series, which should be initialized to some distinctive value using srand.
Because (at least on Linux) pseudo-random number generators are seeded with the same value (to make programs more deterministic, so two consecutive identical runs will give the same answers).
You could seed your PRNG with a different value (the time, the pid, whatever). On Linux you could also consider reading the /dev/urandom (or much rarely, even the /dev/random) pseudo file - often to seed your PRNG.
The code below remembers what random number that was previously picked.
It generates a unique random number only once.
It stores results in an array, so that when rand() produces a number
that already exists, it does not store that number in the array.
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
int size=100;
int random_once[100];
srand(time(0));
cout<<"generating unique random numbers between [0 and "<<size <<"] only once \n\n";
for (int i=0;i<size;i++) // generate random numbers
{
random_once[i]=rand() % size;
//if number already exists, dont store that number in the array
for(int j=0;j<i;j++) if (random_once[j]==random_once[i]) i--;
}
for ( i=0;i<size;i++) cout<<" "<<random_once[i]<<"\t";
cout<<"\n";
return 0;
}
Output :
generating unique random numbers between [0 and 100] only once
50 80 99 16 11 56 48 36 21 34
90 87 33 85 96 77 63 5 60 52
59 4 84 30 7 95 25 1 45 49
10 43 44 82 22 74 32 68 70 86
57 24 39 51 83 2 81 71 42 94
78 72 41 73 92 35 76 9 3 58
19 40 37 67 31 23 55 69 8 17
64 46 93 27 28 91 26 65 47 14
15 75 79 88 62 97 54 12 18 89
13 38 61 0 29 66 53 6 98 20
Press any key to continue