22

My output is 20 random 1's, not between 10 and 1, can anyone explain why this is happening?

#include <iostream> 
#include <ctime> 
#include <cstdlib>

using namespace std;

int main() 
{ 
    srand((unsigned)time(0)); 
    int random_integer; 
    int lowest=1, highest=10; 
    int range=(highest-lowest)+1; 
    for(int index=0; index<20; index++){ 
        random_integer = lowest+int(range*rand()/(RAND_MAX + 1.0)); 
        cout << random_integer << endl; 
    } 
}

output: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Mat
  • 202,337
  • 40
  • 393
  • 406
visanio_learner
  • 373
  • 3
  • 4
  • 12
  • i am only able to generate a 1's, no random number generating is acting on my code, i don't know the actual problem in it, please anyone clear my code... – visanio_learner Feb 28 '12 at 15:22
  • 5
    May I suggest something like `(rand() % range) + lowest` instead? – Some programmer dude Feb 28 '12 at 15:28
  • @JoachimPileborg, your suggestion is really good and it helps, but there is a slight problem, the answer i need is in between 1 and 10, but it produces 0 sometimes and no number 10.... – visanio_learner Feb 28 '12 at 15:45
  • 3
    @Joachim Your suggestion is actually unfortunately really bad, since it makes the random numbers potentially much more biased. – Konrad Rudolph Feb 28 '12 at 20:23
  • For a simple application you can neglect this bias entirely. For scientific computation his idea is really bad of course ... like changing the 10th digit of `pi`. – hochl Feb 29 '12 at 08:54
  • hey friends, int main() { srand((unsigned)time(0)); int random_integer; int lowest=0, highest=10; int range=(highest-lowest)+1; for(int index=0; index<20; index++){ random_integer = (rand() % range) + lowest/(RAND_MAX + 1.0); cout << random_integer << endl; } } "just clear me, i am getting the output from 0 to 10, 11 numbers, but i don't want to get number 10, just numbers 0 to 9, that means 10 random numbers, what should i do" – visanio_learner Mar 01 '12 at 11:37
  • @hochl: So I can also neglect the bias for a simple dice application hosted on some hard money casino website? I mean, it is still simple and not scientific. – Sebastian Mach Mar 01 '12 at 13:07
  • 1
    Of course not, any serious application should use a good random number source. But for simple stuff like audio track shuffling noone will ever notice the difference. – hochl Mar 01 '12 at 14:22

11 Answers11

38

Because, on your platform, RAND_MAX == INT_MAX.

The expression range*rand() can never take on a value greater than INT_MAX. If the mathematical expression is greater than INT_MAX, then integer overflow reduces it to a number between INT_MIN and INT_MAX. Dividing that by RAND_MAX will always yield zero.

Try this expression:

random_integer = lowest+int(range*(rand()/(RAND_MAX + 1.0)))
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
16

It's much easier to use the <random> library correctly than rand (assuming you're familiar enough with C++ that the syntax doesn't throw you).

#include <random>
#include <iostream>

int main() {
  std::random_device r;
  std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
  std::mt19937 eng(seed);

  std::uniform_int_distribution<> dist(1, 10);

  for(int i = 0; i < 20; ++i)
    std::cout << dist(eng) << " ";
}
bames53
  • 86,085
  • 15
  • 179
  • 244
  • Easier? Hhmmm, that is a hard sell ;-). The big reason to use `` is it gives you the flexibility to slot in different random distributions, such as normal or poisson, and to slot in different number random generators that are either better or quicker. – Darren Cook Mar 01 '12 at 00:39
  • Here is an alternative approach using ``: https://gist.github.com/1946214 I have added some comments. It does not require C++11. I hope it shows what is going on. – Darren Cook Mar 01 '12 at 00:41
  • Well, harder to get wrong, say. Also more readable and obvious in intent than using `rand()` correctly. Of course you can wrap the code for using `rand()` into a function that makes it just as readable as `` but since `` already exists, why bother? – bames53 Mar 01 '12 at 02:10
  • I would say it's easier to use this as the reason this question exists is because of the subtle difficulty in converting `rand()` to produce the output you actually need. – the_mandrill Sep 17 '13 at 12:49
11
random_integer = (rand() % 10) + 1 

That should give you a pseudo-random number between 1 & 10.

ryoung
  • 856
  • 1
  • 8
  • 24
  • 7
    Using `%` is bad for your probability distribution, tough in this case it doesn't matter much. – hochl Feb 28 '12 at 15:31
  • ya i know that it's just not the best way to generate a range but it's the simplest one. for more better and complicated one, i prefer @Rob's answer works perfectly – visanio_learner Feb 28 '12 at 15:35
  • 6
    @hochl Using `%` is actually the preferred method, if you have a decent random number generator. Regardless of the method, you have to throw some values away, or accept some bias in the results. – James Kanze Feb 28 '12 at 15:56
  • @JamesKanze: And how do you decide which values to throw away if they are all in [0..10)? – Sebastian Mach Feb 28 '12 at 16:42
  • 4
    @phresnel You throw away certain outputs from `rand()`, before reducing the range. If you want one of ten different values, and `rand()` produces a number of values that are not a multiple of ten, you have to throw some away, or return some of the values in the range more often than others. – James Kanze Feb 28 '12 at 17:03
  • 1
    @JamesKanze I don't know anyone in the Monte Carlo community who advocates using modulus in this way (either ryoungs example of the two step process you describe). The method in Rob's post is messier to read but correct, and it is *idomatic* so you stop reading it. – dmckee --- ex-moderator kitten Feb 28 '12 at 21:06
  • 2
    @dmckee If you're doing serious work with random numbers, and the number of different numbers generated by the random isn't an exact multiple of the number of elements you're interested in, you have to throw out some of the generated random numbers, or you introduce a bias. The people I know who are doing Monte Carlo analysis are generally looking for a `double` result, with as many different values as the generate can give; in this case, of course, you won't use `%`. – James Kanze Feb 29 '12 at 08:33
  • @JamesKanze: Though rejection sampling is suboptimal in many cases. It is great to teach some principles in monte carlo sampling, but to achieve higher performance (i.e. by wasting less results), usually you don't rejection sample on the number generator but transform the number sequences in a way that does not introduce bias (example: when rejection sampling the area of a circle, you waste more than 20% of performance). Thus, I am unsure why you have the impression that `%` is "the preferred method"; usually, all sequences are stretched to [0..1] or [0..1) and then transformed to the range. – Sebastian Mach Feb 29 '12 at 09:12
  • 1
    @phresnel If you're generating discrete values (integers, or something which maps to integers), then there is no possible solution which doesn't involve rejecting some values. You can't put m into n unless n is a multiple of n, if both m and n are integers. As for why `%` is the preferred method, the only real reason is simplicity: why go from integer to float back to integer when you don't have to? – James Kanze Feb 29 '12 at 11:47
  • Just to throw a few numbers into the discussion: The bias we are looking at for `RAND_MAX == INT_MAX` and 32-bit integers is 0.00000047 %. And the percentage of values we would waste using rejection sampling is 0.00000033 %. – Sven Marnach Feb 29 '12 at 23:17
  • As @Sven points out, if you care about the bias you also care about the quality of your random numbers and would think twice about using `rand()`. – Darren Cook Mar 01 '12 at 00:47
  • @JamesKanze: That's of course right. You could statistically smooth the insertion of n values into m slots, however, that would be a far worse solution than modulus and rejection. Of course, another solution is to use a PRNG with state larger than the range of output values, e.g. Mersenne Twister or KISS ([pointers here](http://gitorious.org/picogen/picogen/blobs/master/src/auxiliary/portable_rng/kiss.hh)), so as to "soften" the distribution. – Sebastian Mach Mar 01 '12 at 13:31
9

A somewhat late answer, but it should provide some additional information if the quality of the generation is important. (Not all applications need this—a slight bias is often not a problem.)

First, of course, the problem in the original code is the fact that range * rand() has precedence over the following division, and is done using integer arithmetic. Depending on RAND_MAX, this can easily result in overflow, with implementation defined results; on all implementations that I know, if it does result in overflow (because RAND_MAX > INT_MAX / range, the actual results will almost certainly be smaller than RAND_MAX + 1.0, and the division will result in a value less than 1.0. There are several ways of avoiding this: the simplest and most reliable is simply rand() % range + lowest.

Note that this supposes that rand() is of reasonable quality. Many earlier implementations weren't, and I've seen at least one where rand() % 6 + 1 to simulate a dice throw alternated odd and even. The only correct solution here is to get a better implementation of rand(); it has lead to people trying alternative solutions, such as (range * (rand() / (RAND_MAX + 1.0))) + lowest. This masks the problem, but it won't change a bad generator into a good one.

A second issue, if the quality of the generation is important, is that when generating random integers, you're discretizing: if you're simulating the throw of a die, for example, you have six possible values, which you want to occur with equal probability. The random generator will generate RAND_MAX + 1 different values, with equal probability. If RAND_MAX + 1 is not a multiple of 6, there's no possible way of distributing the values equaly amont the 6 desired values. Imagine the simple case where RAND_MAX + 1 is 10. Using the % method above, the values 1–4 are twice as likely as the the values 5 and 6. If you use the more complicated formula 1 + int(6 * (rand() / (RAND_MAX + 1.0))) (in the case where RAND_MAX + 1 == 10, it turns out that 3 and 6 are only half as likely as the other values. Mathematically, there's simply no way of distributing 10 different values into 6 slots with an equal number of elements in each slot.

Of course, RAND_MAX will always be considerably larger than 10, and the bias introduced will be considerably less; if the range is significantly less than RAND_MAX, it could be acceptable. If it's not, however, the usual procedure is something like:

int limit = (RAND_MAX + 1LL) - (RAND_MAX + 1LL) % range;
            //  1LL will prevent overflow on most machines.
int result = rand();
while ( result >= limit ) {
    result = rand();
}
return result % range + lowest;

(There are several ways of determining the values to throw out. This happens to be the one I use, but I remember Andy Koenig using something completely different—but which resulted in the same values being thrown out in the end.)

Note that most of the time, you won't enter the loop; the worst case is when range is (RAND_MAX + 1) / 2 + 1, in which case, you'll still average just under one time through the loop.

Note that these comments only apply when you need a fixed number of discrete results. For the (other) common case of generating a random floating point number in the range of [0,1), rand() / (RAND_MAX + 1.0) is about as good as you're going to get.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
1

I suggest you replace rand()/(RAND_MAX + 1.0) with range*double(rand())/(RAND_MAX + 1.0)). Since my solution seems to give headaches ...

possible combinations of arguments:

  • range*rand() is an integer and overflows.
  • double(range*rand()) overflows before you convert it to double.
  • range*double(rand()) is not overflowing and yields expected results.

My original post had two braces but they did not change anything (results are the same).

hochl
  • 12,524
  • 10
  • 53
  • 87
  • This doesn’t change a thing since the second operand is already a `double`. – Konrad Rudolph Feb 28 '12 at 20:26
  • funny the OPs version gives all 1 while with this diff it gives random numbers. Did you try it out? – hochl Feb 28 '12 at 21:25
  • The crucial difference is the additional parentheses you used, not the explicit cast to `double`. I should have said that. – Konrad Rudolph Feb 28 '12 at 22:48
  • Sorry but I still don't follow you -- for me one problem with his code is that `range*rand()` is overflowing already, converting `rand()` to `double` will avoid this since `double` has 57 bits of precision. – hochl Feb 29 '12 at 08:47
  • Apologies. I completely forgot about the `range` multiplier, I just looked at your piece of code and saw a redundant cast. You are right. And thanks for being persistent. – Konrad Rudolph Feb 29 '12 at 09:40
1

Visual studio 2008 has no trouble with that program at all and happily generates a swathe of random numbers.

What I would be careful of is the /(RAND_MAX +1.0) as this will likely fall foul of integer problems and end up with a big fat zero.

Cast to double before dividing and then cast back to int afterwards

Rob
  • 335
  • 8
  • 23
  • 1
    `RAND_MAX+1.0` **is** a double, according to *usual arithmetic conversions*, C++03, §5, ¶9. – Robᵩ Feb 28 '12 at 17:13
1
(rand() % highest) + lowest + 1
Rohit Vipin Mathews
  • 11,629
  • 15
  • 57
  • 112
0

It is one of the simplest logics, got it from a blog. in this logic you can limit the random numbers with that given modulus(%) operator inside the for loop, its just a copy and paste from that blog, but any way check it 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

- See more at: http://www.programmingtunes.com/generation-of-random-numbers-c/#sthash.BTZoT5ot.dpuf

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
0

What about using a condition to check if the last number is the same as the current one? If the condition is met then generate another random number. This solution works but it will take more time though.

nelt22
  • 410
  • 1
  • 5
  • 13
0

You are generating a random number (ie (range*rand()/(RAND_MAX + 1.0))) whose value is between -1 and 1 (]-1,1[) and then casting it to an integer. The integer value of such number is always 0 so you end up with the lower + 0

EDIT: added the formula to make my answer clearer

VirtualTroll
  • 3,077
  • 1
  • 30
  • 47
0

Probably "10 * rand()" is smaller than "RAND_MAX + 1.0", so the value of your calculation is 0.

Gandaro
  • 3,427
  • 1
  • 17
  • 19