So I'm trying to run this sim program for a class that makes us build a Bet class using sets.
Here's the class definition:
class Bet2{
private:
set<int> mainNumbers;
set<int> luckyNumbers;
public:
Bet2();
void show() const;
set<int> getMainNumbers();
set<int> getLuckyNumbers();
};
So I decided to use the random lib, since the rand() function that they gave us in class spat out the same values when creating a bunch of Bet2 objects at once, for the sim.
However, for some reason, it's not spitting out the number of values it's supposed to. Sometimes it spits out 4 main numbers (instead of 5), or just 1 lucky number (instead of 2)
Here's the code for the constructor:
Bet2::Bet2() {
random_device rd;
uniform_int_distribution<int> main(1, 50);
for (int i = 0; i < 5; i++)
mainNumbers.insert(main(rd));
uniform_int_distribution<int> star(1, 12);
for (int i = 0; i < 2; i++)
luckyNumbers.insert(star(rd));
}
I ran a few tests using the uniform_int_distribution and the random_device, in the main fucntion, and it ran without any problem. For some reason it eats up values when i initialize a Bet2 vector for my sim:
Main Numbers: 11 23 27 32 36
Star Numbers: 3 11
Main Numbers: 4 18 22 27 28
Star Numbers: 9 11
Main Numbers: 3 5 25 43 <-
Star Numbers: 1 <-
Main Numbers: 40 42 43 46 50
Star Numbers: 2 7
Main Numbers: 7 10 14 27 45
Star Numbers: 9 10
Main Numbers: 11 15 21 24 35
Star Numbers: 1 11
Main Numbers: 3 25 29 45 50
Star Numbers: 3 7
Main Numbers: 11 15 23 25 37
Star Numbers: 1 6
Main Numbers: 7 8 26 31 43
Star Numbers: 6 9
Main Numbers: 15 27 36 38 39
Star Numbers: 2 8
Tried to figure out of uniform_int_distribution can not generate a value, but didnt't find anything online.
Thanks in advance!
std::set can store only up to 1 copy of a given value.
The lack of numbers should be because the random numbers happened to become the same as the numbers that were previously seen.
If you want to store multiples of the same value, you should use std::multiset instead.
If you want to generate a unique set of defined number of values, it may be better to first generate a std::vector of candidate values, and then use std::sample() for that.
Related
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.
Some information about the overall project:
I have to find if specific nodes remain connected if i start removing the lowest width edges from a graph. I have a struct solve, which has a member array called connected. In a method of this struct , FindConnections I go over some of the edges, from the Kth till the last and see which nodes are connected. The way I keep track of the connected nodes is to have an array that for each node points to the lowest id node it is connected, with the lowest pointing to itself
for example
if nodes 2 5 6 12 are directly connected
connected[2] =connected[5] =connected[6] =connected[12] = 2
so now if 12 and 23 are connected (and 12 is the lowest connection of 23)
connected [23] = 12 and connected[connected[23]] = 2 so i can reach 2 from 23 with recursion
My problem is that after finishing modifying the connected array inside FindConnections, some of the changes are preserved while other not
Here is the code:
void FindConnections(int index)
{
for (int temp, i = index; i < NumberOfPortals; i++)
{
temp = min(first[i], second[i]); // the nodes which edge i connects
connected[first[i]] = temp;
connected[second[i]] = temp;
}
}
which is called by
void seeAllConnections() // this function is for visualization it will not be included
{
for (int i = NumberOfPortals - 1; i >= 0; --i)
{
printf("Only using %d Portals:\n", NumberOfPortals - i);
FindConnections(i);
seeconnected(); // prints connected array
for (int i = 0; i < NumberOfUniverses; i++) //resets connected array
{
connected[i] = i;
}
}
}
In the two first iterations of the for loop in seeAllConnections, everything is good, the edges that are examined are
first second width(irrelevant for now)
6 7 255
26 2 111
11 7 36
in the beginning everyone is connected with himself
in the first one we get the output
(I am placing ** around the values that are changed and !! around the one that was supposed to change but didn't , just so you can see it better, the program prints just the numbers)
Only using 1 Portals:
connected are:
0 1 2 3 4 5 6 7 8 9 10 *7* 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
and we can see that connected[11] = 7 just like we wanted to
in the second one
Only using 2 Portals:
connected are:
0 1 2 3 4 5 6 7 8 9 10 *7* 12 13 14 15 16 17 18 19 20 21 22 23 24 25 *2* 27 28 29
connected[11] =7 just like before
connected[26] = 2 just like we wanted
in the third one
Only using 3 Portals:
connected are:
0 1 2 3 4 5 6 !7! 8 9 10 *7* 12 13 14 15 16 17 18 19 20 21 22 23 24 25 *2* 27 28 29
connected [7] = 7 , not 6
moreover, when i use gdb, inside the FindConnections loop, connected[7] = 6 like we wanted
(gdb) print first[i]
$10 = 6
(gdb) print second[i]
$11 = 7
(gdb) print connected[first[i]]
$12 = 6
(gdb) print connected[second[i]]
$13 = 6
but when it exits the function and returns to seeAllConnected
connected[7] = 7
What Am I doing wrong? how can the first two changes be preserved form the same function in the same struct in the same loop, while the second one isn't?
Also after every time I call FindConnections I reset the array to it's original values, so the changes couldn't have been preserved from before
Thank you in advance
I found out what was wrong, as it was a reverse iteration connected[7] got overwritten.
Here is my code which is supposed to write the numbers 0 to 19 on the screen (in random order).
vector<std::function<void(void)>> tasks;
for(int i=0; i<20;i++)
{
tasks.push_back( [&](){cout<< i<<endl;} );
}
tbb::parallel_for(size_t(0), size_t(tasks.size()), [&](int K) {(tasks[K])();});
The out out is:
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
What am I doing wrong? How can I make it to write out the numbers 0 to 19?
You passed a reference to i when adding the new task:
tasks.push_back( [&](){cout<< i<<endl;} );
// ^^^ here
When the task is run, i has reached 20, so that's what each thread will print.
Instead, you probably want to capture a copy of i:
tasks.push_back([=i]{ std::cout << i << '\n'; });
(The = is optional there; I included it to make the point clearer)
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.
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.