//Generate Food Personality
for(i=0; i<food.size(); i++)
{
srand(time(0));
int randomFood = rand() % 6;
if(randomFood == 1 || randomFood == 3 || randomFood == 5)
{
badFood.push_back(food[randomFood]);
}
else if(randomFood == 0 || randomFood == 2 || randomFood == 4)
{
goodFood.push_back(food[randomFood]);
}
}
cout << "Size of Food Vector: " << food.size() << endl;
cout << "Size of Bad Food: " << badFood.size() << endl;
cout << "Size of Good Food " << goodFood.size() << endl;
randomFood is a random number through 6 and it takes the random number in food[] and adds it to
a vector depending on how the random number turns out.
My problem is it seems that its always generating an odd or even number. and the bad and good.size() always prints out as 6 or 0, never anything else.
Calling srand(time(0)); at the beginning of the loop is resetting the random number generator every time through the loop. Thus, you will keep getting the same initial random number every time.
(Technically it would be possible for time(0) to return a different value between iterations of the for loop, but given the speed of today's processors it would be a very rare case when this happens for the code you have provided.)
In any case, you should call srand right before the for loop (or, better yet, just once at the beginning of your program's main routine.)
put the srand() outside of your for loop. You are always reinitializing your random seed.
The problem is that you're seeding your random number generator at the beginning of each loop. Since the loop runs so quickly, it's seeding the same time value every iteration, thus producing the same random number when you call rand.
Also, don't use use the modulo operator with random number generators; that uses the least significant bits (which are almost deterministic) rather than the leading bits (which are closer to being pseudorandom). Divide by six and truncate to an integer instead.
Finally, I'd recommend replacing the superfluous
else if(randomFood == 0 || randomFood == 2 || randomFood == 4)
with
else
Move the srand() outside of the loop.
Your loop is probably taking less than a second each time around, so time(0) is always returning the same value (its resolution is one second), so srand(time(0)) is always seeding the random number generator with the same seed, so rand() is always using the same sequence, so you get the same random number each time around the loop.
You need to move your call to srand above the for loop. This loop is executing very quickly (most likely) so time is returning the same value each time, so you are reseeding your random number generator with the same value, which will generate the same list of psudo-random numbers. You are only using the first member of the same list over and over, until the computer's clock clicks into the next second.
Call srand(time(0)) only once per thread. It shouldn't be called multiple times like in your loop.
I think it's because you are re-seeding the random number generator for each loop iteration. Move srand(time(0)); out side of the for loop
Related
I'm rather new to C++ and I'm trying to implement a simple quadratic congruential random number generator. It seems to work alright but when I test it's period (repeat interval) it doesn't seem to repeat at all. I store the first random number in a variable and then compare the new numbers until the first one is encountered again, and this comparison doesn't ever get triggered. Is my if-statement wrong somehow? Apologies if this is about a stupid bug I can't see.
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
class QCG {
public:
int seed;
int m;
int a;
int b;
int c;
QCG(int seed) {
seed = seed;
m = 1162261467;
a = 14348907;
b = 14348908;
c = 65536;
}
int rand() {
seed = (a*(int)pow(seed, 2) + b*seed + c) % m;
return seed;
}
};
//testing repeat interval
int main() {
QCG qcg(1);
//generate the first number and store it
int first = qcg.rand();
int i = 1;
while (true) {
//this gets triggered when the first value is reached again, i.e. when the period is completed
if (qcg.rand() == first) {
std::cout << "success! period is " << i << std::endl;
break;
}
//this gets triggered if the previous condition isn't met by the maximum possible period
if (i == 1162261468) {
std::cout << "failed" << std::endl;
break;
}
++i;
}
return 0;
}
It goes in a 'rho' shape - first there are some unique numbers, then there is a loop. It doesn't loop back to the first number, but to some further number. Look up Pollard's rho algorithm, or Brent's cycle detection algorithm
You can simply set your first random number as any one of repeated numbers in cycles. It could not go back to the first number directly generated from the seed, because the step size is not fixed and the modulus is a prime number.
However, there will eventually be cycles of repeated numbers, even though a cycle does not contain all integers less than the modulus.
...
int first = qcg.rand();
for (int j = 0; j < 100000; j++)
first = qcg.rand();
int i = 1;
while (true) {
...
In this way, you can make it sure there is the cycle.
We've known since the days of von Neumann's "middle-square method" that while all PRNGs eventually cycle, some can contain multiple sub-cycles of different lengths. This is nicely demonstrated in the directed graph side image linked here. As you can see there, and as #maniek pointed out, there can be subsequences that lead to a cycle but whose values are not within the actual cycle. Wikipedia offers several cycle detection algorithms, with implementations in Python.
A PRNG which doesn't have sub-cyclic behavior, i.e., it produces every possible state before repeating, is called a "full cycle" generator. PRNG testing tends to focus more on the existence of subcycles (proving that the generator is not full cycle) rather than the length of the cycle itself, which can be as small as 1.
This is further complicated by the observations in a paper from the 1980's, which noted that true randomness produces duplicate values without reproducing the sequence from that point forward. That concept led to a test showing that a full cycle PRNG producing values in the range (0, 2k) which doesn't produce any duplicates within 3*2k/2 observations is provably non-random at an α=0.01 level. In other words, if you were generating 32 bit integers but hadn't seen any duplicates within the first 200,000 values, an observer could declare the sequence to be non-random with probability > 0.99. As a result, modern PRNGs use a much larger full cycle internal state space, which they collapse to produce a 32 or 64 bit output. This produces duplicate values without leading to a duplicate sequence.
This question already has answers here:
Random numbers in C
(10 answers)
How can I generate different random numbers for each player?
(3 answers)
Closed 4 years ago.
So I was creating a program that would call a function and return 0 or 1 (0 meaning tails and 1 meaning heads) and then use that to print the outcome of 100 flips.
It seemed simple enough thinking I could use srand(time(NULL)) to seed rand() with constantly varying seeds. Here was my first crack.
#include <stdio.h>
#include <stdlib.h>
int flip();
int main(void) {
int heads = 0;
int tails = 0;
for (short int count = 1; count <= 100; ++count) {
int number = flip();
if (number == 0) {
printf("%s", "Tails");
++tails;
}
else if (number == 1) {
printf_s("%s", "Heads");
++heads;
}
}//end for
printf_s("\n%d Tails\n", tails);
printf_s("%d Heads", heads);
}//end main
int flip(void) {
srand(time(NULL));
int number = (int)rand();
printf("%d", number%2);
return number%2;
}//end flip
I would run the program and my rand() value would always be a five digit integer repeated in each iteration of the for statement (i.e 15367, 15745, or 15943).
I messed around until I discovered changing srand(time(NULL)) to srand(time(NULL)*time(NULL)/rand()) did the trick.
My only thought is that the time between each for iteration is so small the the time(NULL) part of the srand() function doesn't change enough to feed a different seed value.
I also tried srand(time(NULL)/rand()), however, this produced the same result (52 heads 48 tails) every time I ran the program (20+times); however, the rand() values were all different from each other.
I do not know why these things happened, or why the final srand(time(NULL)*time(NULL)/rand()) function worked, and I would love it if someone could explain!
The reason is, that time(NULL) changes only once per second!
This means, that you seed the random number generator 100 times with the same seed.
A better way is to seed the RNG only once at start of the process (at the head of main(), then you should get different values.
If you start your program more often than once a second, you could also seed it with
srand(time(NULL)+getpid());
or similar.
I'm trying to write a piece of code that goes through a random element of a string array and then outputs it. After it outputs it then sets that element to 0. And then that if statement ensures that name will not be outputted again.
void group(){
int random = rand() % 50;
int i, j = 0;
while(j<50){
srand(0);
random = rand() % 50;
groupNum = 1;
cout << "Group " << groupNum << " has: ";
if(names[random] != "0"){
cout << names[random] << " ";
names[random] = "0";
j++;
}
if(names[random] == "0"){
continue;
}
i++;
if(i == peoplePerGroup){
groupNum++;
cout << "\n\n";
i=0;
}
}
}
srand function (as a pseudo-random number generator) should only be seeded once, before any calls to rand(), and the start of the program. It should not be repeatedly seeded, or reseeded every time you wish to generate a new batch of pseudo-random numbers.
"In order to generate random-like numbers, srand is usually initialized to some distinctive runtime value, like the value returned by function time (declared in header ). This is distinctive enough for most trivial randomization needs."
Also, every time your function runs, it's get a random element of your array and sets it to zero. The only way this loop ends is in a scenario that every single elements on this array were setted to zero. Buy in each loop, the index choosed is random. Think about how many times they need to run until they fill your requirements.
As a little explanation to why the re-seeding with the same number causes this issue:
rand() uses pseudo-randomness and therefore it is reproducable. Basically it meshes up some internal number that is set based on the seed. The number for example has bitwise XOR ( ^ ) applied to a constant etc. After every call, the number is also incremented internally.
Naturally that means that with the same starting number (aka the seed) you get the same results every time.
By the way, your whole code becomes much smoother if you fill all your words into an std::set and remove the word from the set when taking it, instead of setting it to null. See here: How to select a random element in std::set?
Or even easier, fill them into a vector and apply: std::random_shuffle
Then just iterate through that vector a single time to receive the words in random order.
As the title states, I'm trying to create a unique sequence of random numbers every time I run this little program.
However, sometimes I get results like:
102
201
102
The code
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 3; i++) {
srand (time(NULL)+i);
cout << rand() % 3;
cout << rand() % 3;
cout << rand() % 3 << '\n' << endl;
}
}
Clearly srand doesn't have quite the magical functionality I wanted it to. I'm hoping that there's a logical hack around this though?
Edit1: To clarify, this is just a simple test program for what will be implemented on a larger scale. So instead of 3 iterations of rand%3, I might run 1000, or more of rand%50.
If I see 102 at some point in its operation, I'd want it so that I never see 102 again.
First of all, if you were going to use srand/rand, you'd want to seed it once (and only once) at the beginning of each execution of the program:
int main() {
srand(time(NULL));
for (int i = 0; i < 3; i++) {
cout << rand() % 3;
cout << rand() % 3;
cout << rand() % 3 << '\n' << endl;
}
Second, time typically only produces a result with a resolution of one second, so even with this correction, if you run the program twice in the same second, you can expect it to produce identical results in the two runs.
Third, you don't really want to use srand/rand anyway. The random number generator in <random> are generally considerably better (and, perhaps more importantly, are enough better defined that they represent a much better-known quantity).
#include <random>
#include <iostream>
int main() {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<int> d(0, 2);
for (int i = 0; i < 3; i++) {
for (int j=0; j<3; j++)
std::cout << d(gen);
std::cout << "\n";
}
}
Based on the edit, however, this still isn't adequate. What you really want is a random sample without duplication. To get that, you need to do more than just generate numbers. Randomly generated numbers not only can repeat, but inevitably will repeat if you generate enough of them (but the likelihood of repetition becomes quite high even when it's not yet inevitable).
As long as the number of results you're producing is small compared to the number of possible results, you can pretty easily just store results in a set as you produce them, and only treat a result as actual output if it wasn't previously present in the set:
#include <random>
#include <iostream>
#include <set>
#include <iomanip>
int main() {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<int> d(0, 999);
std::set<int> results;
for (int i = 0; i < 50;) {
int result = d(gen);
if (results.insert(result).second) {
std::cout << std::setw(5) << result;
++i;
if (i % 10 == 0)
std::cout << "\n";
}
}
}
This becomes quite inefficient if the number of results approaches the number of possible results. For example, let's assume your producing numbers from 1 to 1000 (so 1000 possible results). Consider what happens if you decide to produce 1000 results (i.e., all possible results). In this case, when you're producing the last result, there's really only one possibility left--but rather than just producing that one possibility, you produce one random number after another after another, until you stumble across the one possibility that remains.
For such a case, there are better ways to do the job. For example, you can start with a container holding all the possible numbers. To generate an output, you generate a random index into that container. You output that number, and remove that number from the container, then repeat (but this time, the container is one smaller, so you reduce the range of your random index by one). This way, each random number you produce gives one output.
It is possible to do the same by just shuffling an array of numbers. This has two shortcomings though. First, you need to shuffle them correctly--a Fischer-Yates shuffle works nicely, but otherwise it's easy to produce bias. Second, unless you actually do use all (or very close to all) the numbers in the array, this is inefficient.
For an extreme case, consider wanting a few (10, for example) 64-bit numbers. In this, you start by filling an array with numbers from 264-1. You then do 264-2 swaps. So, you're doing roughly 265 operations just to produce 10 numbers. In this extreme of a case, the problem should be quite obvious. Although it's less obvious if you produce (say) 1000 numbers of 32 bits apiece, you still have the same basic problem, just to a somewhat lesser degree. So, while this is a valid way to do things for a few specific cases, its applicability is fairly narrow.
Generate an array containing the 27 three digit numbers whose digits are less than 3. Shuffle it. Iterate through the shuffled array as needed, values will be unique until you've exhausted them all.
As other people have pointed out, don't keep reseeding your random number generator. Also, rand is a terrible generator, you should use one of the better choices available in C++'s standard libraries.
You are effectively generating a three digit base 3 number. Use your RNG of choice to generate a base 10 number in the range 0 .. 26 and convert it to base 3. That gives 000 .. 222.
If you absolutely must avoid repeats, then shuffle an array as pjs suggests. That will result in later numbers being 'less random' than the earlier numbers because they are taken from a smaller pool.
For part of a programming assignment I need to generate multiple sets of 10 numbers with a range of 1 to 50 with no repeats in each individual set, so I created the following code:
int Numbers[10]; //array to store the random numbers in
bool Duplicate; //variable to check or number is already used
srand(time(NULL)); //seeding the random number generator
// do while loop used to allow user to generate multiple sets
do {
Duplicate = false; // set check to false
//for loop to generate a complete set of 10 random numbers
for (int I = 0; I < 10; I++)
{
// do while loop used to generate random numbers until a distinct random number is generated
do
{
Numbers[I] = (rand()%50) + 1; // generates a random number 1 - 50 and stores it into Numbers[I]
// for loop used to check the other numbers in set for any repeats
for (int J = I - 1; J > -1; J--) // works backwards from the recently generated element to element 0
if (Numbers[I] == Numbers[J]) //checks if number is already used
Duplicate = true; //sets Duplicate to true to indicate there is a repeat
} while (Duplicate); //loops until a new, distinct number is generated
}
//at this point in the program we should have an array Numbers[] with a set of 10 unique random numbers 1 - 50
// loop to print numbers to the screen
for (int I = 0; I < 10; I++)
cout << Numbers[I] << " "; // printing the element to the screen
cout << endl;
cout << "Do you want to run the program again (Y/N): "; // Asks user if they want to create another set of 10 numbers
char Answer; // used to store users answer
cin >> Answer; // stores users answer
} while (Answer == 'Y' || Answer == 'y'); // loop program if the user wants to generate another set
However, I seem to be having trouble with the do while loop that generates random numbers until a new, distinct number is generated.
After some testing and tinkering, I found that I have somehow created an infinite loop there and cannot figure out the problem.
Some ideas that I think may be causing the problem:
-How does the rand function change the seed and is the seed being changed to create a new pseudorandom number?
-Is my for loop to check for repeats outstepping the bounds of the array?
Any advice and hints would be greatly appreciated.
You're forgetting to reset Duplicate back to false. First time it is set to true it remains true, enabling an infinite do...while loop.
Start with an ordered array of 1 to 50, then shuffle it via a Fisher-Yates shuffle. Then just take the first 10 numbers.
Notice that you don't reinitialize Duplicate to false in the beginning of your do-while loop meaning that after you have one duplicate random number - Duplicate is set to true and remains true forever therefore - your do-while loop will run forever.