How does modulus and rand() work? - c++

So, I've been nuts on this.
rand() % 6 will always produce a result between 0-5.
However when I need between, let's say 6-12.
Should I have rand() % 6 + 6
0+6 = 6.
1+6 = 7.
...
5+6 = 11. ???
So do I need to + 7 If I want the interval 6-12? But then, 0+7 =7. When will it randomize 6?
What am I missing here? Which one is the correct way to have a randomized number between 6 and 12? And why? It seems like I am missing something here.

If C++11 is an option then you should use the random header and uniform_int_distrubution. As James pointed out in the comments using rand and % has a lot of issues including a biased distribution:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_int_distribution<int> dist(6, 12);
for (int n = 0; n < 10; ++n) {
std::cout << dist(e2) << ", " ;
}
std::cout << std::endl ;
}
if you have to use rand then this should do:
rand() % 7 + 6
Update
A better method using rand would be as follows:
6 + rand() / (RAND_MAX / (12 - 6 + 1) + 1)
I obtained this from the C FAQ and it is explained How can I get random integers in a certain range? question.
Update 2
Boost is also an option:
#include <iostream>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
int main()
{
boost::random::mt19937 gen;
boost::random::uniform_int_distribution<> dist(6, 12);
for (int n = 0; n < 10; ++n) {
std::cout << dist(gen) << ", ";
}
std::cout << std::endl ;
}

You need rand() % 7 + 6.
Lowest number from rand() %7: 0.
Highest number from rand() %7: 6.
0 + 6 = 6.
6 + 6 = 12.

The modulus operation a % b computes the remainder of the division a / b. Obviously the remainder of a division must be less than b and if a is a random positive integer then a%b is a random integer in the range 0 .. (b-1)
In the comments you mention:
rand()%(max-min)+min
This algorithm produces values in the half-open range [min, max). (That is, max is outside the range, and simply denotes the boundary. Since we're talking about ranges of integers this range is equivalent to the closed range [min, max-1].)
When you write '0 - 5' or '6 - 12' those are closed ranges. To use the above equation you have to use the values that denote the equivalent half open range: [0, 6) or [6, 13).
rand() % (6-0) + 0
rand() % (13-6) + 6
Note that rand() % (max-min) + min is just a generalization of the rule you've apparently already learned: that rand() % n produces values in the range 0 - (n-1). The equivalent half-open range is [0, n), and rand() % n == rand() % (n-0) + 0.
So the lesson is: don't confuse half-open ranges for closed ranges.
A second lesson is that this shows another way in which <random> is easier to use than rand() and manually computing your own distributions. The built-in uniform_int_distribution allows you to directly state the desired, inclusive range. If you want the range 0 - 5 you say uniform_int_distibution<>(0, 5), and if you want the range 6 - 12 then you say uniform_int_distribution<>(6, 12).
#include <random>
#include <iostream>
int main() {
std::default_random_engine eng;
std::uniform_int_distribution<> dist(6, 12);
for (int i=0; i<10; ++i)
std::cout << dist(eng) << " ";
}
rand()%7+6 is more terse, but that doesn't mean it is easier to use.

There are a couple of concepts here.
First, there's the range: [ denotes inclusive. ) denotes exclusive.
The modulus operator % n produces [0,n) - 0,..n-1
When you add a value to that result, you're adding the same value to both ends of the ranges:
%n + 6 = [n,n+6)
Now, if n is 6, as it in in your case, your output will be [0,6)
%6 + 6 = [6,12)
Now what you want is [6,13)
Subtract 6 from that:
[0,7) + 6 => n%7 + 6
Second, there is the matter of using rand(). It depends on whether you really care if your data is random or not. If you do really care that it is random, I highly suggest watching Stefan T Lavalej's talk on the pitfalls of using rand() at Going Native 2013 this year. He also goes into what you should use.
If the randomness of rand() doesn't matter to you, then by all means use it.

Related

random over a range, is number bias present for new rand() version?

reading from various other SO questions, when using rand() % N you may happen to modify the bias for the pseudo number you get, so you usually have to introduce some range handling.
However in all cases rand() was always mentioned, and not the newer random() or arcrandom4() functions or the native C++11 methods. What happens when you run these routines over a set? Do you get a bias like rand()?
Thanks.
The following answer does not go into as much detail as Eric Lippert's blog post on the same topic. Also, this question and its answers deal with the same topic.
Most of the bias that comes from doing rand() % N isn't from the rand() part - it's from the % N part.
Let's consider a 'good' implementation of rand() that generates all numbers from 0 to 100 (picked for simplicity) with equal probability - a uniform distribution. Next let's say that we want to use this implementation of rand() to generate random numbers between 0 and 80, so we do rand() % 80. Let's break down the possibilities of what could happen next:
rand() generates a number from 0 to 79. Any number from 0 to 79 % 80 stays the same number
rand() generates a number from 80 to 100. Any number from 80 to 100 % 80 gets converted to 0 to 20
This means that there are two ways to end up with a number from 0 and 20 but only one way to end up with a number from 21 to 79. Getting a number from 0 to 20 is more likely than getting a number from 21 to 79. This is usually not a desirable property.
Any value of N that divides evenly into the max value of rand() won't have this problem because there will be an equal number of ways to generate any value. Furthermore the bias is much smaller for small values of N than it is for values of N closer to the max value of rand().
So, what about functions other than rand()? If they return values from some fixed range and you do a mod operation, they will suffer from the same bias. If you're calling a random function that takes a range as arguments, then you don't need to do the mod operation. The function will probably handle any biases internally.
What happens when you run these routines over a set? Do you get a bias
like rand()?
The answer is: this depends on the relation between the size of range returned by the generator and the divisor in modulo operation. If divisor not evenly divides the range then distribution will be skewed. The bias ratio is in the range [ 1, 2], where 1 means no bias ( as for uniform distribution) and the bias increases with divisor. Regarding arcrandom4() this translates to skewed distribution obtained in all cases when modulo divisor is not an even divisor of 2^32. The rationale behind it is explained below.
Introduction. The bias
Imagine that we are trying to simulate uniform int distribution over interval [0, 99] with
int x = rand() % 100;
Operator % makes the probability distribution of X skewed because RAND_MAX which is maximum value for rand() can be not equal to k * 100 + 99. This results in that if you imagine all 100-length parts of 0-RAND_MAX range then you can see that last part will probably not produce a full range 0-99. Therefore you have more numbers that generates 0, 1, 2..., p but not necessary p + 1, ..., 98, 99 ( 1 more occurrence for each number in 0, 1, 2, ..., p). The inaccuracy of this approach increases with bigger divisor that not divides the range evenly and maximum bias compared to uniform distribution is equal 2.
In the following sections below we show that the bias measured as a ratio of probability of getting number from [ 0, p] to probability of number from [ p + 1, n] is equal to ( k + 1) / k and we confirm this with 2 examples.
Formula
We will show what exactly is the bias introduced by operation modulo ( operation that is applied to generator of uniform distribution in order to trim the output range). We will operate in terms of formula
x = rand() % ( n + 1)
where rand() is some generator and ( n + 1) is divisor in modulo operation. The picture below shows our standpoint:
We can see how numbers in range [ 0, n] are divided into these that repeat k + 1 times (numbers [ 0, p]) and these that repeats k times ( numbers [ p + 1, n]) in a single trial, which is "take the number from the distribution obtained by x = rand() % (n+1)". The p is defined as a remainder when dividing the maximum number ( i.e. Rand_MAX) given by the generator by the ( n + 1) which is the size of desired range:
p = ( N - 1) % ( n + 1)
N - 1 = k * ( n + 1) + p
and the k is the quotient
k = ( N - 1 - p) / ( n + 1)
In a single trial there are
( p + 1) * ( k + 1) + ( n - p) * k =
= p + 1 + k( n + 1) = N
possible outcomes. Thus the probability of receiving the element that repeats k times is k / N. Let's denote
f_0 = ( k + 1) / N, probability for each element from [ 0, p]
f_1 = k / N, probability for each element from [ p + 1, n]
Let's say that we will express the bias of sampling from this, transformed distribution over the uniform distribution as the ratio of probability of element that belongs to [ 0, p] to probability of element from the range [ p + 1, n]:
bias = f_0 / f_1 = ( k + 1) / k
So, are numbers twice as often?
No. The fact that when we look at the picture numbers repeats doesn't imply the ratio of 2. This ratio is just a special case, if range of the generator is divided into exactly 2 subranges. In general the bias ratio is( k + 1) / k and decreases asymptotically, when divisor n + 1 tends to 1, ( and k tends to N).
Examples
We now consider two simple examples (as suggested by #dyp). First we will generate 1000 * 1000 samples from a distribution given by
x = rand() % m
with generator being std::uniform_int_distribution<> dist(0, 19) and divisor m = n + 1 equal to 15 and next equal to 6.
Example 1
int x = rand() % 15; // n + 1 = 15, rand is uniform distribution over [0,19]
Test program is:
#include <iostream>
#include <random>
#include <vector>
int main()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<> dist(0, 19);
std::vector<int> v(15);
const int runs = 1000 * 1000;
for (int i = 0; i < runs; ++i)
{
++v[dist(mt) % v.size()];
}
for (int i = 0; i < v.size(); ++i)
{
std::cout << i << ": " << v[i] << "\n";
}
}
code
result:
0: 100500
1: 100016
2: 99724
3: 99871
4: 99936
5: 50008
6: 49762
7: 50023
8: 50123
9: 49963
10: 50117
11: 50049
12: 49885
13: 49760
14: 50263
We can see that in this case numbers in range [ 0, p] = [ 0, 4] appears about twice as often as the rest. This is in accordance with our bias formula
bias = f_0 / f_1 = ( k + 1) / k = 2 / 1
Example 2
int x = rand() % 6; // n + 1 = 6, rand is uniform distribution over [0,19]
Test program is:
#include <iostream>
#include <random>
#include <vector>
int main()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<> dist(0, 19);
std::vector<int> v(6);
const int runs = 1000 * 1000;
for (int i = 0; i < runs; ++i)
{
++v[dist(mt) % v.size()];
}
for (int i = 0; i < v.size(); ++i)
{
std::cout << i << ": " << v[i] << "\n";
}
}
code
result:
0: 199875
1: 199642
2: 149852
3: 149789
4: 150237
5: 150605
In this case we observe that numbers in range [ 0, p] = [ 0, 1] appears not about twice as often as the rest but in the ratio of about 20/15. In fact this is 4/3 as our bias formula in this case is
bias = f_0 / f_1 = ( k + 1) / k = 4 / 3
The picture below helps to understand this outcome.
full code
C++11 has solve this problem by adding alternative random generator engines.
The reason why using %(modulo) to constrain your random number to a range is bad has less to do with bias and more to do with the typical implementation of rand(), a linear congruential generator (LCG). Most language runtimes use LCGs for their random function; only very recently designed languages tend to differ.
An LCG is just a multiply and an add (the modulo usually being implemented via an integer’s maximum size). It should be obvious that the low bits of such a sequence follow a regular pattern – the multiply doesn’t mix higher bits into the lower bits, and the add mutates the low bits in a constant way every iteration.
By understanding the different random generators (linear_congruential_engine, mersenne_twister_engine, subtract_with_carry_engine) engines you can find the best one for your application.
there is a very good reference to the new c++ implementations in Random Engines in c++11
As said by #dpy std::uniform_int_distribution is an option given by c++ for random distributions. It treats the bias problem even if the random generator engine has . But if you set a range from 1-19 and store it in a 15 size array by using % operation the bias problem is reintroduced as discussed in many posts here.

Random Number Between 2 Values [duplicate]

This question already has answers here:
How to generate random number within range (-x,x)
(3 answers)
Closed 9 years ago.
Hi i wanna generate a random number between 2 values.
I have 2 variables.
This is the default value:
(MIN = MAX = 1)
Later this value can change!
I have use this:
rand()%(max-min)+min;
But i got debug about division for zero.
Any ideas?
Edit: With the default value the number generated must be 1.
In your initial case (max-min) is 0 and modulus by zero is undefined behavior. From the C++ draft standard section 5.6 Multiplicative operators says:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. [...]
As for generating a random number between min and max you should use the random header and uniform_int_distrubution:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
int min = 1, max = 1 ;
std::uniform_int_distribution<int> dist(min,max);
for (int n = 0; n < 10; ++n) {
std::cout << dist(e2) << ", " ;
}
std::cout << std::endl ;
}
If for some reason C++11 is not an option then the C FAQ gives us the proper formula when using rand in the section How can I get random integers in a certain range? which indicates to generate random numbers in the range [M, N] you use the following:
M + rand() / (RAND_MAX / (N - M + 1) + 1)
The range [min, max] contains max - min + 1 numbers! So your code should have been like this:
rand() % (max - min + 1) + min;
Don't forget to check the value of RAND_MAX though, your range shouldn't get close to that. In fact, you want it to be much smaller than that to avoid too much bias.

How to generate negative random integer in c++

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;

Random number generator, C++

I know there is a bit of limitations for a random number generation in C++ (can be non-uniform). How can I generate a number from 1 to 14620?
Thank you.
If you've got a c++0x environment, a close derivative of the boost lib is now standard:
#include <random>
#include <iostream>
int main()
{
std::uniform_int_distribution<> d(1, 14620);
std::mt19937 gen;
std::cout << d(gen) << '\n';
}
This will be fast, easy and high quality.
You didn't specify, but if you wanted floating point instead just sub in:
std::uniform_real_distribution<> d(1, 14620);
And if you needed a non-uniform distribution, you can build your own piece-wise constant or piece-wise linear distribution very easily.
A common approach is to use std::rand() with a modulo:
#include<cstdlib>
#include<ctime>
// ...
std::srand(std::time(0)); // needed once per program run
int r = std::rand() % 14620 + 1;
However, as #tenfour mentions in his answer, the modulo operator can disrupt the uniformity of values std::rand() returns. This is because the modulo translates the values it discards into valid values, and this translation might not be uniform. For instance, for n in [0, 10) the value n % 9 translates 9 to 0, so you can get zero by either a true zero or a 9 translated to zero. The other values have each only one chance to yield.
An alternative approach is to translate the random number from std::rand() to a floating-point value in the range [0, 1) and then translate and shift the value to within the range you desire.
int r = static_cast<double>(std::rand()) / RAND_MAX * 14620) + 1;
srand() / rand() are the functions you need, as others have answered.
The problem with % is that the result is decidedly non-uniform. To illustrate, imagine that rand() returns a range of 0-3. Here are hypothetical results of calling it 4000 times:
0 - 1000 times
1 - 1000 times
2 - 1000 times
3 - 1000 times
Now if you do the same sampling for (rand() % 3), you notice that the results would be like:
0 - 2000 times
1 - 1000 times
2 - 1000 times
Ouch! The more uniform solution is this:
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
Sorry for the sloppy code, but the idea is to scale it down properly to the range you want using floating point math, and convert to integer.
Use rand.
( rand() % 100 ) is in the range 0 to 99
( rand() % 100 + 1 ) is in the range 1 to 100
( rand() % 30 + 1985 ) is in the range 1985 to 2014
( rand() % 14620 + 1 ) is in the range 1 to 14620
EDIT:
As mentioned in the link, the randomizer should be seeded using srand before use. A common distinctive value to use is the result of a call to time.
As already said, you can use rand(). E.g.
int n = rand() % 14620 + 1;
does the job, but it is non-uniform.
That means some values (low values) will occur slightly more frequently. This is because rand() yields values in the range of 0 to RAND_MAX and RAND_MAX is generally not divisible by 14620. E.g. if RAND_MAX == 15000, then the number 1 would be twice as likely as the number 1000 because rand() == 0 and rand() == 14620 both yield n==1 but only rand()==999 makes n==1000 true.
However, if 14620 is much smaller than RAND_MAX, this effect is negligible. On my computer RAND_MAX is equal to 2147483647. If rand() yields uniform samples between 0 and RAND_MAX then, because 2147483647 % 14620 = 10327 and 2147483647 / 14620 = 146886, n would be between 1 and 10328 on average 146887 times while the numbers between 10329 and 14620 would occur on average 146886 times if you draw 2147483647 samples.
Not much of a difference if you ask me.
However, if RAND_MAX == 15000 it would make a difference as explained above.
In this case some earlier posts suggested to use
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
to make it 'more uniform'.
Note that this only changes the numbers that occur more frequently since rand() still returns 'only' RAND_MAX distinct values.
To make it really uniform, you would have to reject any integer form rand() if it is in the range between 14620*int(RAND_MAX/14620) and RAND_MAX and call rand() again.
In the example with RAND_MAX == 15000 you would reject any values of rand() between 14620 and 15000 and draw again.
For most application this is not necessary. I would worry more about the randomness of rand().
Here's a tutorial using the boost library http://www.boost.org/doc/libs/1_45_0/doc/html/boost_random/tutorial.html#boost_random.tutorial.generating_integers_in_a_range
The rand() function is not really the best Random generator, a better way would be by using CryptGenRandom().
This example should do do the trick:
#include <Windows.h>
// Random-Generator
HCRYPTPROV hProv;
INT Random() {
if (hProv == NULL) {
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
ExitProcess(EXIT_FAILURE);
}
int out;
CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out));
return out & 0x7fffffff;
}
int main() {
int ri = Random() % 14620 + 1;
}
the modulus operator is the most important, you can apply a limit with this modulus, check this out:
// random numbers generation in C++ using builtin functions
#include <iostream>
using namespace std;
#include <iomanip>
using std::setw;
#include <cstdlib> // contains function prototype for rand
int main()
{
// loop 20 times
for ( int counter = 1; counter <= 20; counter++ ) {
// pick random number from 1 to 6 and output it
cout << setw( 10 ) << ( 1 + rand() % 6 );
// if counter divisible by 5, begin new line of output
if ( counter % 5 == 0 )
cout << endl;
}
return 0; // indicates successful termination
} // end main

C++ How I can get random value from 1 to 12? [duplicate]

This question already has answers here:
Generating a random integer from a range
(14 answers)
Closed 6 years ago.
How I can get in C++ random value from 1 to 12?
So I will have 3, or 6, or 11?
Use the following formula:
M + rand() / (RAND_MAX / (N - M + 1) + 1), M = 1, N = 12
and read up on this FAQ.
Edit: Most answers on this question do not take into account the fact that poor PRN generators (typically offered with the library function rand()) are not very random in the low order bits. Hence:
rand() % 12 + 1
is not good enough.
#include <iomanip>
#include <iostream>
#include <stdlib.h>
#include <time.h>
// initialize random seed
srand( time(NULL) );
// generate random number
int randomNumber = rand() % 12 + 1;
// output, as you seem to wan a '0'
cout << setfill ('0') << setw (2) << randomNumber;
to adress dirkgently's issue maybe something like that would be better?
// generate random number
int randomNumber = rand()>>4; // get rid of the first 4 bits
// get the value
randomNumer = randomNumer % 12 + 1;
edit after mre and dirkgently's comments
Is there some significance to the leading zero in this case? Do you intend for it to be octal, so the 12 is really 10 (in base 10)?
Getting a random number within a specified range is fairly straightforward:
int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
*/
int divisor = RAND_MAX/(limit+1);
int retval;
do {
retval = rand() / divisor;
} while (retval > limit);
return retval;
}
(The while loop is to prevent skewed results -- some outputs happening more often than others). Skewed results are almost inevitable when/if you use division (or its remainder) directly.
If you want to print it out so even one-digit numbers show two digits (i.e. a leading 0), you can do something like:
std::cout << std::setw(2) << std::setprecision(2) << std::setfill('0') << number;
Edit: As to why this works, and why a while loop (or something similar) is needed, consider a really limited version of a generator that only produces numbers from, say, 0 to 9. Assume further that we want numbers in the range 0 to 2. We can basically arrange the numbers in a table:
0 1 2
3 4 5
6 7 8
9
Depending on our preference we could arrange the numbers in columns instead:
0 3 6
1 4 7
2 5 8
9
Either way, however, we end up with the one of the columns having one more number than any of the others. 10 divided by 3 will always have a remainder of 1, so no matter how we divide the numbers up, we're always going to have a remainder that makes one of the outputs more common than the others.
The basic idea of the code above is pretty simple: after getting a number and figuring where in a "table" like one above that number would land, it checks whether the number we've got is the "odd" one. If it is, another iteration of the loop is executed to obtain another number.
There are other ways this could be done. For example, you could start by computing the largest multiple of the range size that's still within the range of the random number generator, and repeatedly generate numbers until you get one smaller than that, then divide the number you receive to get it to the right range. In theory this could even be marginally more efficient (it avoids dividing the random number to get it into the right range until it gets a random number that it's going to use). In reality, the vast majority of the time, the loop will only execute one iteration anyway, so it makes very little difference what we execute inside or outside the loop.
You can do this, for example:
#include <cstdlib>
#include <cstdio>
#include <time.h>
int main(int argc, char **argv)
{
srand(time(0));
printf("Random number between 1 and 12: %d", (rand() % 12) + 1);
}
The srand function will seed the random number generator with the current time (in seconds) - that's the way it's usually done, but there are also more secure solutions.
rand() % 12 will give you a number between 0 and 11 (% is the modulus operator), so we add 1 here to get to your desired range of 1 to 12.
In order to print 01 02 03 and so on instead of 1 2 3, you can format the output:
printf("Random number between 01 and 12: %02d", (rand() % 12) + 1);
(rand() % 12 + 1).ToString("D2")