I am new to c++. I am trying to generate 4 random unique numbers from 0 to 9. Here is my code:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<int> vect;
int randNums = 4;
int countSameNums = 0;
int randNumber;
srand(time(0)); // Initialize random number generator by setting the seed
// generate 4 random unique integers and insert them all into a vector
while (true){
randNumber = rand()%10;
for (int i = 0; i < vect.size(); i++){
if (randNumber == vect[i]){
countSameNums += 1;
}
}
if (countSameNums == 0){
vect.push_back(randNumber);
countSameNums = 0;
}
if (vect.size() == randNums)
break;
}
for (int el : vect){ // print out the content of the vector
cout << el <<endl;
}
}
I can compile the code without problems. However when I run it, sometimes it prints out the correct result, i.e. the 4 unique integers, but other times the program just hangs. I also notice that If I comment the line srand(time(0)) (my random seed) it prints 4 unique numbers every time, i.e. the program never hangs. The problem of course is that by commenting srand(time(0)) I get always the same sequence of unique numbers and I want a different sequence every run. Any idea on why this isn't working? thanks
It can take long before you get 4 different numbers. There is a simpler and more efficient way to get 4 unique numbers. Take a vector containung number from 0 till 9, shuffle it, take the first 4.
Anyhow the issue in your code is that once countSameNum is not 0 you will never reset it to 0. You only reset it when it is 0 already. Change it like this:
while (true){
randNumber = rand()%10;
countSameNums = 0;
for (int i = 0; i < vect.size(); i++){
if (randNumber == vect[i]){
countSameNums += 1;
}
}
if (countSameNums == 0){
vect.push_back(randNumber);
}
if (vect.size() == randNums)
break;
}
As this is rather error-prone you should rather use std::find to see if the number is already in the vector:
if (std::find(vect.begin(),vect.end(),randNumber) == vect.end()) vect.push_back(randNumber);
And as mentioned before, there are better ways to get unique random numbers.
Related
I need to find a way to fill an array with random numbers without having duplicates,so i wrote this code and it works.My question is,is this code efficient and will it really have no duplicates? Thanks in advance!
#include <iostream>
#include <time.h>
#include <stdlib.h>
int main(void) {
srand(time(NULL));
std::size_t array_size=100;
int array[array_size];
for(int i=0;i<array_size;i++) {
array[i]=rand()%105+1;
for(int k=0;k<array_size;k++) { // Checks if there is a duplicate in the array //
if(i!=k) { // Don't check for the same array position //
if(array[i]==array[k]) { // If a duplicate is found,repeat the check process//
array[i]=rand()%105+1;
k=-1; // -1 so the for loop starts from zero //
}
}
}
}
return 0;
}
That approach works fine when the number of desired values is much less than the number of possible values. Most of time it won't produce a duplicate value, so it just keeps the one it produced. But when there isn't a lot of slack there are lots of duplicates; when this code gets close to the end it's generating a value between 1 and 106 when there are only six or seven or so acceptable values. So it ends up spinning its wheels.
Instead of doing all that looping, create an array that holds all of the possible values, randomly shuffle it, and throw out the extra ones:
int array[105];
for (int i = 0; i < 105; ++i)
array[i] = i + 1;
std::mt19937_64 mt;
std::shuffle(std::begin(array), std::end(array), mt);
for (int i = 0; i < 100; ++i)
std::cout << array[i] << '\n';
I am writing a code that is supposed to act as a lottery. The lottery numbers available are 1-50, and there are 10 of them. The user is supposed to input one number and the program returns if the user's number matches one of the 10 random lottery numbers. I have gotten all of these parts down, but there is one problem; all 10 of the lottery numbers must be unique. I have gotten 10 unique numbers 1-50, but they weren't very random. The code I have written up to this point seems correct to me, except I know there is something missing (along with the fact that I can clean my code up a lot, but I'm focusing on the objective right now). Right now if I run the program it will return ten zeroes. I need each element in the lottery array to be a unique number from 1-50, and produce different sets of numbers each time i run the program. Any help would be appreciated.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using std::cout; using std::cin; using std::endl;
void printOut(int[]);
void draw(int[]);
bool check();
int fillFunc[10];
int main()
{
const int arraySize = 10;
int win[arraySize] = {};
srand((unsigned)time(NULL));
draw(win);
cout << "Your lottery numbers are: ";
printOut(win);
}
void draw(int fillFunc[])
{
int i;
for (i = 0; i < 10; i++)
{
if (check() == true)
continue;
fillFunc[i] = 1 + rand() % 50;
}
}
void printOut(int fillFunc[])
{
for (int i = 0; i < 10; i++)
{
cout << " " << fillFunc[i];
}
cout << "\n";
}
bool check()
{
for (int i = 0; i < 10; ++i)
{
if (fillFunc[i] == i)
return true;
}
return false;
}
(also don't ask me why the array has the name "win", this is what my prof wants me to call it)
Because check() always return true. At the start, the array is filled with zeroes so check returns true as win[0]==0 and that remains true forever as nothing changes that value. So in draw you always branch to continue and never modify anything.
To solve the problem one way could be to shuffle the sequence of 1-50 and extract the first 10 values of the shuffled array. You can use the very simple Fisher-Yates algorithm.
To answer your question that you updated in the comments you need to consider a shuffling algorithm.
I will give you an idea of how to do this that is O(n) so you don't have to "loop" thru your current list of numbers and keep checking to see if the new number was already picked...
your lottery max number is 50 so make an array of size 50 that is as follows:
lotteryNumber[0]=1
lotteryNumber[1]=2
...
lotteryNumber[49]=50
to pick a number to put into your "selected" numbers array...
indexToLotteryNumbers = rand() % 50 - numbersPickedSoFar;
randomLotteryNumber[i++] = lotteryNumber[ indexToLotteryNumbers ];
// this is the key "trick"
swap(&lotteryNumber[ indexToLotteryNumbers ], &lotteryNumber[49-numbersPickedSoFar]);
numbersPickedSoFar++;
Theory
The random numbers are the indexes and not the actual values
By swapping the number you picked with the outer element you don't care if your random number generator picks the same index because it will be different the next time.
look at a small example...say you have 1 2 3 4
rand() generates "2"
so your first # is 2 (assume 1-based indexing here) now you swap the (4th) element for the (2nd) element now you have 1 4 3 |2
(here |2 means you can't pick that number again because it's outside the
random # generator range) but you reduce the random # generation from
1-4 to 1 thru 3
rand() generates "1" so your number is "1" and you swap that with the "outer" unpicked number 3 4 |1 2
rand() generates
"2" again! your lottery number is 4 this time... and so on.
I hope this makes sense.
This is what I would do, given your constraints. Rather than check if a number is unique while you are filling the array, just pass the array into the function that chooses the number so it can return a unique value.
I also removed the redundant global array. It could be a source of bugs if you forgot to pass the local array you were working with to any of the functions.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int getUniqueNumber(int fillFunc[])
{
while(true)
{
//pick number
int val = 1 + rand() % 50;
//assume it's unique
bool unique = true;
for (int i = 0; i < 10; ++i)
{
//if another number matches, it isn't unique, choose again
if (fillFunc[i] == val)
{
unique = false;
break;
}
}
//if it is unique, return it.
if (unique)
{
return val;
}
}
//never reached, but avoids an all control paths must return a value warning.
return -1;
}
void draw(int fillFunc[])
{
for (int i = 0; i < 10; i++)
{
fillFunc[i] = getUniqueNumber(fillFunc);
}
}
void printOut(int fillFunc[])
{
for (int i = 0; i < 10; i++)
{
cout << " " << fillFunc[i];
}
cout << "\n";
}
int main()
{
srand((unsigned)time(NULL));
const int arraySize = 10;
int win[arraySize] = {};
draw(win);
cout << "Your lottery numbers are: ";
printOut(win);
return 0;
}
There are other, perhaps better, ways to select unique numbers in a range, but I went for simple to implement and explain. You can read about some other methods in these questions:
Unique random numbers in an integer array in the C programming language
Unique (non-repeating) random numbers in O(1)?
You only assign a value to fillFunc[i] when i is 10, which is an out of bounds access. Move the assignment to inside the loop.
You have other problems too. If you do continue, you just leave an entry in the array unset.
You should try adding a lot of output statements to your program so you can more easily understand what it's doing. If you prefer, use a debugger to step through it.
This question already has answers here:
Random array generation with no duplicates
(9 answers)
Closed 5 years ago.
I want to generate random numbers and save them in an array. that' all ! but here is the point, I want to avoid duplicating and not having a number two or more times in array.
my code :
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main()
{
int k, temp;
cin >> k;
int sym[k];
srand(time(NULL));
for (int i = 0; i < k; i++)
{
temp = rand() % 25 + 97;
for(int j=0; j<i; j++)
{
while(temp == sym[j])
{
temp = rand() % 25 + 97; // 25 means a and 122 means z
}
}
sym[i] = temp;
}
for(int i=0; i<k; i++)
{
cout << sym[i] << endl;
}
return 0;
}
I still get duplicated results.
I will use std::unordered_set to avoid duplicated
Random generator doesn't mean unique generation, collisions can always happen especially when the number of generated values is high and the bounds or limits for the generation is small...
to avoid duplicated elements replace this array
int sym[k];
by a set which is a container that doesn't allow duplicate entries...
std::set<int>
after that, you need to replace the logic because looping k times does not mean having k elements in the set, so you need to do a while loop until the size of the set reaches the limit k
Edit:
if you need some unsorted generated values, the instead of using a set, consider implementing an unordered_set
This question already has answers here:
How to make Random Numbers unique
(6 answers)
Closed 6 years ago.
As a part of code for a certain game I want to generate 4 unique random numbers into a vector.
This code works for some number of repeated plays and then application crashes (not responding window).
While I understand that if-condition prevents for-loop from inserting the same number into a vector, how much time does this for-loop takes until it generates unique numbers via rand() function?
How srand(time(NULL)) and rand() exactly work together to create random values depending on the system time?
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
//plays bulls and cows
int main() {
srand(time(NULL));
string play="yes";
int nums=4; // number of values in an answer (must NOT exceed 10)
vector<int> answer;
while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game
answer.push_back(rand()%10+1);
do { //fills vector with unique random numbers
for (int i=1; i<nums; i++) {
answer.push_back(rand()%10+1);
if (answer[i]==answer[i-1]) {
i=i-1;
continue;
}
}
} while (answer.size()!=nums);
for (int i=0; i<nums; i++) {
cout<<answer[i];
}
cout<<"Do you want to play again?"<<'\n';
cin>>play;
answer.clear();
} //game ends
if (play=="no" || play=="n" || play=="No" || play=="NO" || play=="N") { //terminates and checks for exceptions
cout<<"Thank you for playing!"<<'\n';
return 0;
} else {
cerr<<"Error: wrong input. Terminating."<<'\n';
return 0;
}
return 0; //safety return
}
Why do you add the new try into answer instead of temporary variable. If the variable is valid, then add it into the answer. In your case, i always keep at 1;
while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game
int last_try=rand()%10+1;
answer.push_back(last_try);
do { //fills vector with unique random numbers
int new_try=rand()%10+1;
if (last_try!=new_try)
{
answer.push_back(new_try);
last_try=new_try;
}
} while (answer.size()!=nums);
for (int i=0; i<nums; i++)
{
cout<<answer[i]<<"\n";
}
cout<<"Do you want to play again?"<<'\n';
cin>>play;
answer.clear();
} //game ends
Assume that you must use std::vector (and not a std::set). The easiest way to fill your vector with random numbers is to check to see if the number has already been "seen" -- if not, then add it to the vector.
This can be accomplished by using an array of bool as a helper to determine if the number has been seen:
#include <vector>
#include <iostream>
#include <cstdlib>
int main()
{
std::vector<int> answer;
int num = 4;
// 10 numbers
bool seen[10] = {false};
// keeps track of numbers added
int numsAdded = 0;
while (numsAdded < num)
{
int numRand = rand()%10;
if ( !seen[numRand] )
{
// not seen, so add it to vector and update bool array and
// numsAdded
answer.push_back(numRand + 1);
seen[num] = true;
++numsAdded;
}
}
for (size_t i = 0; i < num; ++i)
std::cout << answer[i] << " ";
}
Live Example
The problem is you always push back the random value in your vector before checking if it's valid. Let's say your program generates these random value in order:
2, 6, 6, 7, 9, 10
What happens is you will insert 2 (i == 2), 6 (i == 3), 6 (i == 4), then realize 6 is repeated twice, so you go back one iteration (i == 3), but both your sixes are still in your vector. So now you will add 7 (i == 4) and you will exit the for loop with 5 values in your vector.
Then when you evaluate your do-while condition, your answer.size() won't ever equal 4 because it already is equal to 5. You are now stuck in an infinite loop, and your application crashes when it consumes all the available memory from your vector growing infinitely.
Also, you appear to have an error in your logic. To make sure you don't have a repeated value (and you are stuck with vectors), you should not only validate the last inserted value but the whole vector. Like this:
#include <algorithm>
if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
do_this();
else
do that();
So I made a simple prime number finder for the numbers between 3 and 200. It has to use a boolean variable, just fyi. No errors occur. output is:
The prime numbers between 3 and 200 are:
3
5
7
Why does it not keep going? I have drawn it out on paper time and again and cannot find my logic error.
In addition; I wrote this out by hand because I do not know how to get the contents of my file. It exists on a remote host which I do not have root access to. Is there a better way to copy the file?
#include <iostream>
using namespace std;
int main()
{
int count=0;
cout<<"The prime numbers between 3 and 200 are: "<<endl;
for (int i=3;i<=200;i++)
{
for (int j=2;j<i;j++)
{
bool ptest=i%j;
if (!ptest)
{
break;
}
else if (ptest)
{
count=count+1;
if (count==(i-2))
cout<<i<<endl;
}
}
}
}
You forgot to set count back to 0 after using it in the j loop. Move the line:
int count = 0;
to be inside the first for loop. Then your program works correctly (although as msw indicated, it is not the most efficient technique!)
Some things to consider:
You don't need to consider any even numbers in your code.
You have some logic errors in your code. The value of count needs to be checked after the second for loop. count needs to be reset before the second for loop begins.
You can stop immediately after you find the number is not prime in the inner loop instead of continuing on. You can just use a flag isPrime instead of counting.
Here's a version of the code that works for me:
#include <iostream>
using namespace std;
int main()
{
cout << "The prime numbers between 3 and 200 are: " <<endl;
for (int i=3; i <= 200; i += 2) {
bool isPrime = true;
for (int j=3; j < i; j += 2) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime)
{
cout << i << endl;
}
}
}
You don't have to loop till j reach i, instead you can check if j < sqrt(i) ,i.e. write in the second for loop: for (int j=3; j*j<=i; j+=2)