2

I'm using the ncurses library to build a game. I'm having trouble generating the correct random numbers. The while loop below needs to keep generating random numbers until they are between 1 and 45(this is my y-axis limits on the standard screen). I can't figure out what I'm doing wrong because the while loop condition looks fine to me. The problem is that while loop starts running infinitely. Im not doing anything but printing the generated numbers at the end as i just want to see that the correct numbers are generated. can anyone please help me with this problem? The following is my int main.

int main()
{
int r,c,x=0;
initscr();
raw();
keypad(stdscr, TRUE);
noecho();
//mvprintw(22,45,"<");
getmaxyx(stdscr,r,c);

int n,n2 = 0;

while((n<1)||(n>45)){
srand (time(NULL));
n = rand();
srand (time(NULL));
n2 = rand();
}
mvprintw(4,10,"First Random Number: %d\n", n);
mvprintw(5,10,"Second Random number: %d\n", n2);

getch();
endwin();
return 0;
}
Ching Ling
  • 301
  • 1
  • 5
  • 14
  • 3
    First of, don't call `srand` multiple times, it will give very poor results. Second of, why are you just calling plain `rand()` instead of something like `(rand()%45)+1` ? – UnholySheep Oct 10 '14 at 14:11
  • There's a bunch of problems with `rand()`, you might find this http://www.lesinskis.com/code_repair_01_rand_problems.html to be interesting. – shuttle87 Oct 10 '14 at 14:14
  • 3
    C or C++ ? answers will vary immensely. – quantdev Oct 10 '14 at 14:14
  • Oh yeah.. not using srand 2 times. although it didnt make any difference. and I'm only trying to get a reasonable output right now. I haven't worked much on improving the rand result. but yeah you're right doing that will improve the rand result. however, for now i can't seem to jump out of the loop and display the result. any thoughts on that? – Ching Ling Oct 10 '14 at 14:16

4 Answers4

4

This is how you can do it in C++:

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen( rd());
    std::uniform_int_distribution<> dis( 1, 45);

    for (int n=0; n<1000; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}

Using rand() % x is a flawed design because of the bias introduced be dividing a range not evenly. You can read this to learn more about the bias introduced by rand() % x.

Community
  • 1
  • 1
4pie0
  • 29,204
  • 9
  • 82
  • 118
  • 3
    In most cases, `rand()` is just fine. The bias that comes from unequal division is minor and, short of _serious_ distribution requirements, irrelevant. Getting it to choose your 6-from-45 Lotto numbers, for example, is not really n issue :-) Still, it's a good answer, showing the newer C++ random stuff. – paxdiablo Oct 10 '14 at 14:30
  • 1
    @paxdiablo Yes you are right, just wanted to warn... – 4pie0 Oct 10 '14 at 14:34
  • @paxdiablo, `rand()` should be avoided. It doesn't generate random numbers. – CroCo Oct 10 '14 at 15:05
  • 1
    @CroCo true, but please keep in mind that for some things, applications it is just enough – 4pie0 Oct 10 '14 at 15:07
  • @0d0a, I don't understand. Anyone who wants to use `rand()`, he expects randomness. There is no meaning of saying this is just fine or enough even with very simple game like rolling a die. – CroCo Oct 10 '14 at 15:13
  • sometimes you chose poor quality judiciously because of some from a set of n reasons – 4pie0 Oct 10 '14 at 15:18
  • 1
    CroCo, the Mersenne twister doesn't generate random numbers either, that's why they're called pseudo random number generators. Their properties are well known and they're suitable for all but the most demanding use. – paxdiablo Oct 10 '14 at 22:13
2

You want to call srand once at the start of things and then use modulus to bring rand results into your range, something like:

srand(time(NULL));
n  = rand() % 45 + 1;
n2 = rand() % 45 + 1;
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • 1
    this doesn't provide uniform distribution because of bias – 4pie0 Oct 10 '14 at 14:17
  • 4
    @0d0a The author (of the question) did not specify that he needs uniform distribution – UnholySheep Oct 10 '14 at 14:18
  • but he assumed this, this is what a random means to him IMO – 4pie0 Oct 10 '14 at 14:21
  • yeah uniform distribution is not really required. it just needs to be random. This should work thanks. – Ching Ling Oct 10 '14 at 14:24
  • @UnholySheep you see, as expected – 4pie0 Oct 10 '14 at 14:25
  • 2
    @0d0a I don't get it - he just said that "uniform distribution is not really required"? what about that is expected? – UnholySheep Oct 10 '14 at 14:27
  • OP indirectly assumes uniform distribution, this is what means uniform to him – 4pie0 Oct 10 '14 at 14:28
  • 3
    Err, "uniform distribution is not really required" - OP _directly_ states uniform distribution irrelevant, or that's how it appears to me :-) – paxdiablo Oct 10 '14 at 14:33
  • Bottom line, you should not use `rand()` see this video. http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful and to appreciate the meaning of randomness, you should play a game that depends on random generators. This is why you lose or win a lot in some games because the random numbers are bias. – CroCo Oct 10 '14 at 14:58
  • CroCo, this opinion that you shouldn't use rand because it doesn't give truly random numbers seems a little strange. At no point does the standard guarantee true randomness, and the algorithms used for _pseudo_ RNGs are well known. For the vast majority of cases, they're perfectly adequate. – paxdiablo Oct 10 '14 at 23:11
1

Just like @unholySheep commented, rand() returns a value between 0 and RAND_MAX, which it a huge value. Therefore, it is very unlikely you will get quickly a value between 1 and RAND_MAX.

Therefore, the solution is to do the reminder of the division by the number you want:

 n = 1 + rand() % 45;

You do not even need a while.

Alberto
  • 499
  • 4
  • 23
  • 1
    this is flawed design – 4pie0 Oct 10 '14 at 14:16
  • because of [bias introduced by rand](http://stackoverflow.com/questions/24067831/random-over-a-range-is-number-bias-present-for-new-rand-version/24069874#24069874) – 4pie0 Oct 10 '14 at 14:27
1

You can get a random number between 1 and 45 inclusive with:

n = rand() % 45 + 1;

It won't be perfect in terms of distribution but it'll be close enough for anyone who's neither a statistician nor a cryptographer, in which case you probably would be using real random numbers.

You should also call srand() once, at the start of your program somewhere, rather than multiple times, especially if you're using the current time to seed it.

Doing it multiple times within the same second will give you a decidedly non-random sequence such as:

42, 42, 42, 42, 42, 42, 42, ...
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953