Thread: Prelude's random numbers tutorial

  1. #1
    FOX
    Join Date
    May 2005
    Posts
    188

    Prelude's random numbers tutorial

    Why does this code from her tutorial only print out negative numbers? I thought it was supposed to print out numbers between 1-10.
    Code:
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    
    int main()
    {
      std::srand ( (unsigned int)std::time ( 0 ) );
      std::cout<< (int)( (double)std::rand() / ( RAND_MAX + 1 ) * 10 ) <<std::endl;
    
      return 0;
    }
    I don't understand how (double)std::rand() / ( RAND_MAX + 1 ) could ever be a negative number, unless rand() is generating one (which would seem a tad odd). Or maybe it's (RAND_MAX + 1) that is somehow overflowing to -RAND_MAX?

    EDIT: It is indeed (RAND_MAX+1) that is overflowing.
    Last edited by ^xor; 06-10-2005 at 07:57 AM.

  2. #2
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Quote Originally Posted by ^xor
    Or maybe it's (RAND_MAX + 1) that is somehow overflowing to -RAND_MAX?
    That's it exactly. I remember seeing that code a while back and thinking it was wrong. It should be:
    Code:
    std::cout<< (int)( ((double)std::rand() /  RAND_MAX) * 10 + 1) <<std::endl;
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  3. #3
    FOX
    Join Date
    May 2005
    Posts
    188
    Yeah I kinda figured it out now myself. Maybe someone should modify the tutorial?

  4. #4
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    What compiler, on vc beta express... RAND_MAX IS #DEFINE as 32767 or something close so it's not even coming close to overflowing There is no way that this should output a negative.

  5. #5
    FOX
    Join Date
    May 2005
    Posts
    188
    On Linux with glibc, RAND_MAX is the same size as INT_MAX.

  6. #6
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Assuming 2-byte integers, it does. I miss 2-byte integers.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  7. #7
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    rand() / RAND_MAX * 10 + 1

    In the above expression rand() / RAND_MAX will give a decimal number with a value between 0 and 1 inclusively. Therefore

    rand() / RAND_MAX * 10 will give a number between 0 and 10, inclusive and

    rand() / RAND_MAX * 10 + 1

    will give a number between 1 and 11, inclusive. That's well and good if that is your intention. However (as I remember it) the intention of the original equation

    rand() / (RAND_MAX + 1) * 10

    was to generate a "random" digit, 0 - 9, inclusive, (and I believe with each value 0-9 being obtained with "equal" frequency given a large sample size). In order to do that, the denominator needs to be at least numerator + 1 for any possible value of the numerator, so the maximal size of the numerator + 1 was chosen as the denominator. That way the ratio is always less than 1 and greater than or equal to zero and the product, when casted to an int, is always 0 - 9. If RAND_MAX is defined as INT_MAX then adding 1 will cause the value to be negative. If it is a simple negation (that is INT_MAX + 1 == -INT_MAX) then you can overcome that by using the absolute value, which is available as abs(). I forget though whether INT_MAX + 1 == -(INT_MAX) or -(INT_MAX - 1).
    You're only born perfect.

  8. #8
    Registered User
    Join Date
    Jul 2003
    Posts
    110
    Disclaimer: I haven't read Prelude's tutorial (does anyone have a link?), so I fear I may be working off of false assumptions. Please accept my deepest apologies if that turns out to be the case.


    EDIT: It is indeed (RAND_MAX+1) that is overflowing
    You could either change it to (RAND_MAX + 1L) to convert to long arithmetic, or even (RAND_MAX + 1U) for unsigned, but a more reliable way of generating random numbers [1...10] is:

    Code:
    std::rand() * 9.0 / RAND_MAX + 1;
    However, if the intent was to generate integers [1...10], then this isn't it. The basic idea is to divide up the range of values into 10 "buckets" that the result of rand() will "fall" into. Imagine holding a ball in your hand, and tossing it at the 10 buckets with your eyes closed. Whichever one the ball hits is your number. Simply divide RAND_MAX by 10, and round up for the remainder:

    Code:
    const int bucket_size = RAND_MAX / 10 + 1;
    Now, just take the result of rand() divided by bucket_size, and you will have a result [0...9]. All that's left is to add 1 for the offset.

    Code:
    int r = std::rand() / bucket_size + 1;
    HTH,
    Will

  9. #9
    FOX
    Join Date
    May 2005
    Posts
    188
    Quote Originally Posted by whoie
    You could either change it to (RAND_MAX + 1L) to convert to long arithmetic, or even (RAND_MAX + 1U) for unsigned, but a more reliable way of generating random numbers [1...10] is:

    Code:
    std::rand() * 9.0 / RAND_MAX + 1;
    That's not a very reliable way at all actually. The only way to generate 10 that way, would be for rand() to generate RAND_MAX. That's a 1/RAND_MAX chance of happening, which is clearly way below the other numbers (1-9).

    Your other solution works perfectly though.
    Code:
    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    
    int main(void)
    {
            unsigned int i;
            std::srand((unsigned int)std::time(NULL));
            for (i=0; i<50; i++)
                    std::cout << (int) (std::rand() / (RAND_MAX / 10 + 1)) << std::endl;
    
            return 0;
    }

  10. #10
    C/C++Newbie Antigloss's Avatar
    Join Date
    May 2005
    Posts
    216
    If it is to generate a random number between 0 and n, why not use:
    Code:
    std::srand((unsigned int)std::time(NULL));
    std::cout << std::rand() % (n+1) << std::endl;
    and
    Code:
    std::srand((unsigned int)std::time(NULL));
    std::cout << std::rand() % n + 1 << std::endl;
    will generate a number between 1 and n

  11. #11
    FOX
    Join Date
    May 2005
    Posts
    188
    From Prelude's tutorial:
    snip... unfortunately the modulo method uses the low order bits of the random number generator. This is bad because poor generators will create non-random sequences when using low order bits for small ranges. The way to improve this is to force the use of high order bits instead by using a value defined in cstdlib called RAND_MAX
    There's also a note in the man pages for rand.

  12. #12
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >(int)( (double)std::rand() / ( RAND_MAX + 1 ) * 10 )
    That's a typo, good catch. It came from here:
    Code:
    double r0 = (double)rand() / ( RAND_MAX + 1 );
    I was lazy and just cut and pasted without looking. The intention was:
    Code:
    (double)rand() / RAND_MAX + 1;
    >maybe it's (RAND_MAX + 1) that is somehow overflowing to -RAND_MAX?
    It's RAND_MAX + 1 that's causing undefined behavior. Since RAND_MAX is most likely to be interpreted as a signed integral value, and signed integer overflow is a Bad Thing(tm).

    I've been meaning to update all of my tutorials, maybe I should use this as a good reason.
    My best code is written with the delete key.

  13. #13
    FOX
    Join Date
    May 2005
    Posts
    188
    That makes it:
    Code:
    std::cout<< (int)( (double)std::rand() * 10.0 / RAND_MAX + 1) <<std::endl;
    But that's still not the same as:
    Code:
    std::cout << (int) (std::rand() / (RAND_MAX / 10 + 1) + 1) << std::endl;
    The first code generates numbers in the range 1-11 (the 11 only has 1/RAND_MAX of being generated), while the second code generates in the range 1-10 with proper distribution.

  14. #14
    email for MystWind avatar MystWind's Avatar
    Join Date
    Feb 2005
    Location
    Holland , The Hague
    Posts
    88
    yep.
    PLay MystWind beta , within two years

  15. #15
    Registered User
    Join Date
    Jul 2003
    Posts
    110
    Originally Posted by whoie
    You could either change it to (RAND_MAX + 1L) to convert to long arithmetic, or even (RAND_MAX + 1U) for unsigned, but a more reliable way of generating random numbers [1...10] is:


    Code:
    std::rand() * 9.0 / RAND_MAX + 1;
    Quote Originally Posted by ^xor
    That's not a very reliable way at all actually. The only way to generate 10 that way, would be for rand() to generate RAND_MAX. That's a 1/RAND_MAX chance of happening, which is clearly way below the other numbers (1-9).

    I'm afraid we misunderstood each other. When I initially wrote that, I wasn't sure if the intent was to generate random integers [1...10] or random "real" numbers. It is obvious now (and should have been at the time with the cast to int that I neglected to notice) that the intent was to generate integers.

    But you should look the code above again to see if you really understood what the probability is for all possible results. I think you will find that all results have a 1 / (RAND_MAX + 1) probability. Not just 10.

    In hindsight, it was totally irrelevant to the discussion, and I'm sorry for any confusion.

    Will

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. questions....so many questions about random numbers....
    By face_master in forum C++ Programming
    Replies: 2
    Last Post: 07-30-2009, 08:47 AM
  2. Generatin Random Numbers
    By dantu1985 in forum C Programming
    Replies: 15
    Last Post: 08-13-2007, 01:21 AM
  3. Generating 100k to 1 million unique random numbers
    By Ariod in forum C Programming
    Replies: 4
    Last Post: 08-26-2005, 12:59 PM
  4. random number tutorial
    By 7stud in forum C++ Programming
    Replies: 3
    Last Post: 07-26-2005, 02:41 PM
  5. Random numbers (about the tutorial)
    By face_master in forum C++ Programming
    Replies: 3
    Last Post: 08-26-2001, 06:56 AM