I want to draw 1 integer from [1,10] a large number of times, then check how many times each integer appears. I wrote this code, it is compiling but showing segmentation fault. Can you, please, point out where the problem is?
#include <iostream>
#include <random>
#include <array>
int main(){
std::random_device rd;
std::mt19937 dre(rd());
std::uniform_int_distribution <int> di(1,10);
std::array<int,10> count{0};
for(int i=0;i<10000;++i)
{
int rand=di(dre);
count[rand]++;
}
for (int foo: count){
count[foo]/=10000;
std::cout << foo << " " << count[foo] << std::endl;
}
}
If you define an array consisting of 10 elements, like you do here:
std::array<int,10> count{0};
Then the array will have indices 0-9. So count will range from count[0] to count[9].
However, here:
count[rand]++;
when rand is 10, you're trying to access count [10], which doesn't exist.
To answer the followup question in your edit, you're looping round and creating 10000 random numbers, here:
for(int i=0;i<10000;++i)
{
int rand=di(dre);
And as you're picking between 10 different numbers, you'd expect the count of each one to be approximately 1000, with a uniform distribution.
However, when you come to print the results, you divide each count by 10000:
count[foo]/=10000;
So this means it's highly likely that each count is now approx 0.1. As you're storing it in an int, this gets rounded down to zero.
You call count[rand] where count has 10 items, meaning indices in the range of 0..9 but rand is in the range of 1..10 so every once in a while it will call count[10] which causes your seg fault.
Make the distribution use [0..9] instead: std::uniform_int_distribution <int> di(0,9);
With for (int foo: count), foo is equal to each element in count in turn. You need to use foo on its own in the loop instead of count[foo], or use an explicit for loop if you need the index.
Additionally, std::uniform_int_distribution is bounds-inclusive, so you need to initialize it with 0, 9 instead of 1, 10 to index into your ten-elements count.
Your uniform distribution should be defined as:
std::uniform_int_distribution <int> di(0, 9);
because your array elements are indexed from 0 to 9. As-is your rand variable will eventually become greater than 9 at which point you are reading out of bounds thus causing undefined behavior. Even if rand stays within boundaries your range based for loop will exhibit UB because foo there is the value of the actual array element yet used as an index. Should be passed by reference instead:
for (int& foo : count) {
foo /= 10000;
std::cout << foo << '\n';
}
Also if you are using C++11 then you will need double braces for the std::array initializer here:
std::array<int, 10> count{ { 0 } };
Related
I'm new to C++, and I've been searching all day to find a way to randomly select one of two distinct integers.
Everything I've found so far works only for integers within a range (1-10, etc) rather than for (1 or 3).
For ex. code I've been using elsewhere in the program (for a range of numbers) is
int c;
int Min = 1;
int Max = 3;
c = rand() % (Max + 1 - Min) + Min;
which returns a random integer within the range, rather than one or the other integers given.
First of all you shouldn't use C random in C++. Use C++ random.
The way to chose from a set of elements is to randomly generate an index. You can wrap the logic in a class:
#include <random>
#include <iostream>
#include <vector>
#include <initializer_list>
class Random_choice
{
std::random_device rd_{};
public:
template <class T> auto get_choice(std::initializer_list<T> elements) -> T
{
std::uniform_int_distribution<std::size_t> dist{0, elements.size() - 1};
std::size_t i = dist(rd_);
return *(elements.begin() + i);
}
};
int main()
{
Random_choice rc;
std::cout << rc.get_choice({3, 5}) << std::endl;
}
Or without the abstraction:
#include <random>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> choices = {3, 5};
std::random_device rd;
std::mt19937 e{rd()};
std::uniform_int_distribution<std::size_t> dist{0, choices.size() - 1};
std::size_t i = dist(e);
std::cout << choices[i] << std::endl;
}
Randomly choosing one of two integers, a or b:
c = (rand() % 2) ? a : b
Randomly choosing an integer from a list of integers:
std::vector<int> numbers;
c = numbers.at(rand() % numbers.size());
Randomly choosing an integer from two intervals [a, b) and [c, d):
H = (b-a);
L = (b-a) + (d-c);
k = rand() % L;
c = (k < H) ? (a + k) : (c + (k - H));
In case you do C++11 then you may definitely have look into pseudo-random numer generation, like discrete_distribution and uniform_int_distribution.
Update. Removed the claim that we would choose uniformly from the given set. Since rand() chooses from [0, RAND_MAX], this is only true if the divisor of the above modulo operations divides (RAND_MAX+1). (Which is true for the first example in most implementations where RAND_MAX is 32767 or another power-of-two minus 1.) However, the defect from being uniform is roughly of the order of divisor/RAND_MAX. Nevertheless, C++11 uniform_int_distribution is recommended instead. Thanks, Baum mit Augen.
If you have a range of numbers that you don't want numbersin, then you have two ranges that you do want numbers in.
For example, if your range is 1 to 3 (inclusive) then the two ranges you do want numbers in are -∞ to 0, and 4 to ∞.
Infinity is a little tricky on computers, but can easily be emulated for example by std::numeric_limits to get the min and max for the wanted type.
So in your case you want a random number in the range std::numeric_limits<int>::min() to 0, and 4 to std::numeric_limits<int>::max().
Two get two random numbers from a random choice of either range, first pick (randomly) one range, and get a number from that. Then again (randomly) pick a range and get the second number from that.
I have been trying a sorting method in which I subtract each number stored in an array by other elements in the same array. Then, I saw a pattern that the number of differences which come to be negative, is the rank or position of element in the Sorted one. But, things go wrong when I am using repeated entries.
My basic method is :
Take every element of the SampleArray.
subtract it from every element of the SampleArray
check if the difference comes to be negative.
if it is then, increase a variable called counter.
And use this counter as the position of element in sorted array.
For example: lets take (5,2,6,4)
first take 5, subtract it from each of the numbers which will give results (0,-3,1,-1), so counter will become 2, which will be the index of 5 in the sorted Array. And repeat it for each of the elements.
for 5, counter will be 2.
for 2, counter will be 0.
for 6, counter will be 3.
for 4, counter will be 1.
And hence the sorted Array will be {2,4,5,6}.
First, see the code :
#include <iostream>
using namespace std;
void sorting(int myArray[], int sizeofArray);
int main()
{
int checkArray[] = {5,4,2,20,12,13,8,6,10,15,0}; //my sample Arry
int sized;
sized=sizeof checkArray/sizeof(int);//to know the size
cout << sized << endl;
sorting(checkArray, sized);
}
void sorting(int myArray[], int sizeofArray)
{
int tempArray[sizeofArray];
for (int i=0; i<sizeofArray; i++)
{
int counter=0;
for (int j=0;j<sizeofArray; j++ )
{
int checkNum = myArray[j]-myArray[i];
if (checkNum<0)
counter++; //to know the numbers of negatives
else
counter+=0;
}
tempArray[counter]=myArray[i];
}
for (int x=0;x<sizeofArray; x++)
{
cout << tempArray[x] << " " ;
}
}
Now, if we run this program with entries with no repetitions then, it sorts out the array, But if we use repeated entries like
int checkArray[] = {8,2,4,4,6}
the tempArray gets its first element as 2 as counter will be zero.
the tempArray gets its second element as 4 as counter will be 1.
but, the tempArray can't get its third one as counter will be still 1, and thus prints some randomNo in place of this. (here the things go wrong).
Can you please suggest a method to solve this?
This is an odd way of writing insertion sort, https://en.wikipedia.org/wiki/Insertion_sort
I would assume you can change your condition to:
if (checkNum<0 || (checkNum==0 && j<i))
But I would suggest using a proper sorting routine instead
The idea is to separate duplicates by saying that if the values are the same we sort according to their order in the sequence; as if the sequence was a pair of the value and the sequence number (0, 1, 2, 3, 4, 5, ...).
The issue here is that for any 2 equally sized numbers the nested loop will return the same counter value. Thus for such a counter value tempArray[counter + 1] will never be initialized.
The way to solve this would be to maintain a vector<bool> denoting what each position had been written and write to the next valid position if that is the case.
But supporting a second vector is just going to make your O(n2) code slower. Consider using sort instead:
sort(begin(checkArray), end(checkArray))
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.
I am very new to C++. I am basically self teaching. I came across a Hangman game project that I am using for practice. My problem is to do with the random word generation.
I know that for example int n=rand()% 10 means generate random numbers from range 0 to 10.
Now in the game there is an array with 10 elements for the ten words. What I am confused about is that if numbers from 0 to 10 is randomly generated, that would be a selection from 11 random numbers. However the array only has 10 elements (0-9).
What happens when the random generator chooses 10? Element 10 does not exist in the array, right?
So should this code not have been int n=rand()% 9 instead?
Also, could the same word be repeated before all words have been selected in the game? That would obviously not be ideal. If it could, then how do I prevent this?
I know that for example int n=rand()% 10 means generate random numbers
from range 0 to 10.
Not exactly. Generated range is then [0,9].
Side note: in C++11 you should use better random number generator: std::uniform_int_distribution
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen( rd());
// here (0,9) means endpoints included (this is a call to constructor)
std::uniform_int_distribution<> dis(0, 9);
std::cout << dis(gen) << std::endl; // std::endl forces std::cout to
// flush it's content, you may use '\n'
// instead to buffer content
return 0;
}
If you try to subscript array with out-of-range index then it is a disaster named Undefined Behavior:
Undefined behavior and sequence points
What are all the common undefined behaviours that a C++ programmer should know about?
You misunderstand ranges and modulus in C/C++: Ranges include the first element, but (usually) not the last element. Hence, the range [0, 10) is 0,1,2,3,...,9.The modulus is mathematical, the expression x % 10 clamps the result to the range [0, 10), which is 0,1,2,3,...,9
There are 100 numbers present in an array and I need to find out the average of top 5 highest numbers among them.
Also in the same way the average of top 5 lowest numbers among them. How could I go about doing it?
Use Hoare's select algorithm (or the median of medians, if you need to be absolutely certain of the computational complexity), then add the top partition (and divide by its size to get the average).
This is somewhat faster than the obvious method of sorting instead of partitioning -- partitioning is (O(N)) where sorting is O(N log(N) ).
Edit: In C++, for real code (i.e., anything except homework where part of the requirement is to do the task entirely on your own) you can use std::nth_element to partition the input into the top 5 and everything else.
Edit2: Here's another quick demo to complement #Nils', but this one in full C++11 regalia (so to speak):
#include <numeric>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main(){
std::vector<int> x {1, 101, 2, 102, 3, 103, 4, 104, 5, 105, 6};
auto pos = x.end() - 5;
std::nth_element(x.begin(), pos, x.end());
auto sum = std::accumulate(pos, x.end(), 0);
auto mean = sum / std::distance(pos, x.end());
std::cout << "sum = " << sum << '\n' << "mean = " << mean << "\n";
return 0;
}
Jerry already explained how it works. I just want to add a practical code-example in c++:
#include <algorithm>
int averageTop5 (int list[100])
{
// move top 5 elements to end of list:
std::nth_element (list, list+95, list+100);
// get average (with overflow handling)
int avg = 0;
int rem = 0;
for (int i=95; i<100; i++)
{
avg += list[i]/5;
rem += list[i]%5;
}
return avg + (rem /5);
}
With Jerrys std::accumulate this becomes a two-liner but may fail with integer overflows:
#include <algorithm>
#include <numeric>
int averageTop5 (int list[100])
{
std::nth_element (list, list+95, list+100);
return std::accumulate (list+95, list+100, 0)/5;
}
Sort them in ascending and add the last five numbers
Copy the first 5 numbers into an array. Determine the position of the smallest element in that array. For each of the 95 numbers in the remainder of the list, compare it with that smallest number. If the new number is larger, then replace it and redetermine the position of the new smallest number in your short list.
At the end, sum your array and divide by 5.