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.
Related
I need to generate random numbers between two values in c++, which can be generated like that(in a range 1 to 6)
:
#include <iostream>
#include <random>
int main(int argc, char* argv[]){
srand(time(NULL));
for (int j = 0; j < 6 ; j++) {
randomNumber = rand() % 6 + 1;
cout << randomNumber;
return 0;
}
But I also need to ensure that it generates at least once each number in the range, for example: range [1,6], you must generate at least once the 1,2,3,4,5 and 6.
And there is another thing, the numbers generated, must be evenly distributed, like if want generate 20 iterations in range of[1,6], each number(1,2,3,4,5,6) should have approximately the same quantity generated at 20 iterations. Example: 1,3,5,2,4,6,2,4,6,1,3,5,6,5,4,3,5,2,1.... and not like this: 1,3,5,6,6,6,2,6,4,4,4,4,4,4...
If anyone knows how to solve this, I'll be very grateful to you.
Thanks!!!
This is where the C++ Standard Library comes to the rescue. Typed off the top of my head:
#include <random>
int get_rand_in_1_6()
{
static std::random_device rnd;
return std::uniform_int_distribution <int> ( rnd )( 1, 6 );
}
The result will be uniformly-distributed.
(You may not get one of each in the first six iterations, though. Being uniformly distributed does not guarantee any specific values in any specific sub-interval, only that the number is just as likely as any other to appear. Given enough iterations, you will see that.)
[edit 2]: IDR the exact mathematical formula for minimum number of iterations to guarantee that you see each number at least once — I am wildly guessing around 15 for the minimum number of pulls to guarantee that.
If I understand correctly, std::shuffle might help you:
std::random_device rd;
std::mt19937 gen(rd());
int numbers[] = {1, 2, 3, 4, 5, 6};
for (int j = 0; j < 20 ; j++) {
if (j % 6 == 0) { std::shuffle(numbers, numbers + 6, gen); }
std::cout << numbers[j % 6];
}
Demo
You have then sequence of random permutations.
I was wondering if there was a way to have a random number between A an b and where if a number meets a certain requirement it is more likely to appear than all the other numbers between A and B, for example: Lower numbers are more likely to appear so if A = 1 and B = 10 then 1 would be the likeliest and 10 would be the unlikeliest.
All help is appreciated :) (sorry for bad English/grammar/question)
C++11 (which you should absolutely be using by now) added the <random> header to the C++ standard library. This header provides much higher quality random number generators to C++. Using srand() and rand() has never been a very good idea because there's no guarantee of quality, but now it's truly inexcusable.
In your example, it sounds like you want what would probably be called a 'discrete triangular distribution': the probability mass function looks like a triangle. The easiest (but perhaps not the most efficient) way to implement this in C++ would be the discrete distribution included in <random>:
auto discrete_triangular_distribution(int max) {
std::vector<int> weights(max);
std::iota(weights.begin(), weights.end(), 0);
std::discrete_distribution<> dist(weights.begin(), weights.end());
return dist;
}
int main() {
std::random_device rd;
std::mt19937 gen(rd());
auto&& dist = discrete_triangular_distribution(10);
std::map<int, int> counts;
for (int i = 0; i < 10000; i++)
++counts[dist(gen)];
for (auto count: counts)
std::cout << count.first << " generated ";
std::cout << count.second << " times.\n";
}
which for me gives the following output:
1 generated 233 times.
2 generated 425 times.
3 generated 677 times.
4 generated 854 times.
5 generated 1130 times.
6 generated 1334 times.
7 generated 1565 times.
8 generated 1804 times.
9 generated 1978 times.
Things more complex than this would be better served with either using one of the existing distributions (I have been told that all commonly used statistical distributions are included) or by writing your own distribution, which isn't too hard: it just has to be an object with a function call operator that takes a random bit generator and uses those bits to produce (in this case) random numbers. But you could create one that made random strings, or any arbitrary random objects, perhaps for testing purposes).
Your question doesn't specify which distribution to use. One option (of many) is to use the (negative) exponential distribution. This distribution is parameterized by a parameter λ. For each value of λ, the maximum result is unbounded (which needs to be handled in order to return results only in the range specified)
(from Wikipedia, By Skbkekas, CC BY 3.0)
so any λ could theoretically work; however, the properties of the CDF
(from Wikipedia, By Skbkekas, CC BY 3.0)
imply that it pays to choose something in the order of 1 / (to - from + 1).
The following class works like a standard library distribution. Internally, it generates numbers in a loop, until a result in [from, to] is obtained.
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
class bounded_discrete_exponential_dist {
public:
explicit bounded_discrete_exponential_dist(std::size_t from, std::size_t to) :
m_from{from}, m_to{to}, m_d{0.5 / (to - from + 1)} {}
explicit bounded_discrete_exponential_dist(std::size_t from, std::size_t to, double factor) :
m_from{from}, m_to{to}, m_d{factor} {}
template<class Gen>
std::size_t operator()(Gen &gen) {
while(true) {
const auto r = m_from + static_cast<std::size_t>(m_d(gen));
if(r <= m_to)
return r;
}
}
private:
std::size_t m_from, m_to;
std::exponential_distribution<> m_d;
};
Here is an example of using it:
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
bounded_discrete_exponential_dist d{1, 10};
std::vector<std::size_t> hist(10, 0);
for(std::size_t i = 0; i < 99999; ++i)
++hist[d(gen) - 1];
for(auto h: hist)
std::cout << std::string(static_cast<std::size_t>(80 * h / 99999.), '+') << std::endl;
}
When run, it outputs a histogram like this:
$ ./a.out
++++++++++
+++++++++
+++++++++
++++++++
+++++++
+++++++
+++++++
+++++++
++++++
++++++
Your basic random number generator should produce a high-quality, uniform random numbers on 0 to 1 - epsilon. You then transform it to get the distribution you want. The simplest transform is of course (int) ( p * N) in the common case of needing an integer on 0 to N -1.
But there are many many other transforms you can try. Take the square root, for example, to bias it to 1.0, then 1 - p to set the bias towards zero. Or you can look up the Poisson distribution, which might be what you are after. You can also use a half-Gaussian distribution (statistical bell curve with the zero entries cut off, and presumably also the extreme tail of the distribution as it goes out of range).
There can be no right answer. Try various things, plot out ten thousand or so values, and pick the one that gives results you like.
You can make an array of values, the more likely value has more indexes and then choose a random index.
example:
int random[55];
int result;
int index = 0;
for (int i = 1 ; i <= 10 ; ++i)
for (int j = i ; j <= 10 ; ++j)
random[index++] = i;
result = random[rand() % 55];
Also, you can try to get random number twice, first time you choose the max number then you choose your random number:
int max= rand() % 10 + 1; // This is your max value
int random = rand() % max + 1; // This is you result
Both ways will make 1 more likely than 2 , 2 more likely than 3 ... 9 more likely than 10.
I want to generate an exponentially-spaced list of numbers in C++, where the number of points and the bounds are known (just like Matlab's linspace or logspace, or Python's numpy.logspace). I have found several implementations for log-spaced numbers (see below), but couldn't think of a way to invert these to exponentially-spaced numbers, besides, bounds can be negative.
Here's is what I have found so far :
Is there something like numpy.logspace in C++?
EXPLIST: Stata module to generate an exponentially-spaced list of numbers (No idea what this language is actually)
Generating a logarithmically spaced numbers
EDIT :
I should have given the problem a little more thinking before rushing to stackoverflow, here's what I actually did (inspired by this question) :
Given two bounds first and last, I wanted to generate a n-size array that starts with first and ends with last where each array's element is the exponential of some x.
This mathematical problem is a simple series U(i) that starts with U(0) = first and ends with U(n) = last with U(i) = first * q^i (for i in {0, 1, ..., n}) and q = pow(last / first, 1 / (n - 1)).
Here's a raw code :
#include <Eigen\Dense>
using namespace Eigen;
VectorXd expList(double first, double last, DenseIndex n)
{
VectorXd vector(n); // native C++ array or vector can be used of course
double m = (double) 1 / (n - 1);
double quotient = pow(last / first, m);
vector(0) = first;
for (DenseIndex i = 1; i < n; i++) // DenseIndex is just a typedef ptrdiff_t from the Eigen library
vector(i) = vector(i - 1) * quotient;
return vector;
}
This works for any same sign doubles first and last where first < last of course, but It can work for a negative first and positive last too with a little tweaking.
Example :
for first = 50 and last = 300 000 and a 100 elements array
I assume what you mean is a list of doubles (d1,...,dn) such that e^d(i+1)-e^di is constant?
In that case the following function should do what you want:
#include <vector>
#include <math.h>
#include <iostream>
std::vector<double> explist(double first, double last, double size)
{
if(first>last) std::swap(first,last);
double expfirst = exp(first);
double explast = exp(last);
double step = (explast-expfirst)/(size-1);
std::vector<double> out;
for(double x=expfirst; x<=explast; x+=step)
{
double a = log(x);
out.push_back(a);
}
return out;
}
int main()
{
std::vector<double> test = explist(0,1,6);
for(double d : test)
{
std::cout<<d<<" ";
}
std::cout<<std::endl;
for(double d : test)
{
std::cout<<exp(d)<<" ";
}
std::cout<<std::endl;
}
Output:
0 0.295395 0.523137 0.708513 0.86484 1
1 1.34366 1.68731 2.03097 2.37463 2.71828
At the moment this function only produces ascending lists (it just assumes that the smaller value is the left bound). There are several ways to make it work for descending lists as well (always assuming the leftmost argument to be the left bound). I just wanted to make the function as simple as possible and I think if you understand the function it will be easy for you to add that functionality.
I wrote a function that takes integers. It won't crash if the user types for example, -5, but it will convert it into positive =-(
int getRandoms(int size, int upper, int lower)
{
int randInt = 0;
randInt = 1 + rand() % (upper -lower + 1);
return randInt;
}
What should I change in the function in order to build random negative integers?
The user inputs the range.
There are two answers to this, if you are using C++11 then you should be using uniform_int_distribtion, it is preferable for many reasons for example Why do people say there is modulo bias when using a random number generator? is one example and rand() Considered Harmful presentation gives a more complete set of reasons. Here is an example which generates random integers from -5 to 5:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_int_distribution<int> dist(-5, 5);
for (int n = 0; n < 10; ++n) {
std::cout << dist(e2) << ", " ;
}
std::cout << std::endl ;
}
If C++11 is not an option then the method described in C FAQ in How can I get random integers in a certain range? is the way to go. Using that method you would do the following to generate random integers from [M, N]:
M + rand() / (RAND_MAX / (N - M + 1) + 1)
For a number in the closed range [lower,upper], you want:
return lower + rand() % (upper - lower + 1); // NOT 1 + ...
This will work for positive or negative values, as long as upper is greater than or equal to lower.
Your version returns numbers from a range of the same size, but starting from 1 rather than lower.
You could also use Boost.Random, if you don't mind the dependency. http://www.boost.org/doc/libs/1_54_0/doc/html/boost_random.html
You want to start by computing the range of the numbers, so (for example) -10 to +5 is a range of 15.
You can compute numbers in that range with code like this:
int rand_lim(int limit) {
/* return a random number in the range [0..limit)
*/
int divisor = RAND_MAX/limit;
int retval;
do {
retval = rand() / divisor;
} while (retval == limit);
return retval;
}
Having done that, getting the numbers to the correct range is pretty trivial: add the lower bound to each number you get.
Note that C++11 has added both random number generator and distribution classes that can take care of most of this for you.
If you do attempt to do this on your own, when you reduce numbers to a range, you pretty much need to use a loop as I've shown above to avoid skew. Essentially any attempt at just using division or remainder on its own almost inevitably introduces skew into the result (i.e., some results will happen more often than others).
You only need to sum to the lower-bound of the range [lbound, ubound]:
int rangesize = ubound - lbound + 1;
int myradnom = (rand() % rangesize) + lbound;
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.