I noticed something with rand and I'm looking for some explanation.

Discussion in 'C Programming' started by mulligan.kyle, Mar 8, 2013.

  1. Hello, I am taking an introductory course in C and had an assignment recently that involved rand(). I noticed something interesting and was hoping someone might be able to explain.

    My program allows the user to input an upper and lower floating point boundand my randBetween function returns a floating point number between those two bounds. My program works, however I noticed something strange when dealing with large numbers. For small numbers for my bounds, with a small range, the number printed would have several values after the decimal. However, for large numbers as my bounds with a similar range, only a few actual numbers are printed after the decimal followed by several 0's.

    Here are some examples of outputs:

    enter lower and upper limits separated by a comma: 20,33
    Your random number is 30.922440
    (the range between these bounds is 13)

    enter lower and upper limits separated by a comma: 1234567,1234575
    Your random number is 1234573.750000
    (the range between these bounds is also 13 but less numbers are printed after the decimal)

    Here is my program, please note that I understand how to seed the rand function but chose not to, however I did some testing with multiple seeds.



    float randomBetween(float, float);

    float userInput1,
    printf("enter lower and upper limits separated by a comma: ");
    scanf("%g,%g", &userInput1,&userInput2);
    randomNumber=randomBetween(userInput1, userInput2);
    printf("Your random number is %f\n", randomNumber);

    float randomBetween(float userInput1,float userInput2)
    float random,
    random = ((float) rand()) / (float) RAND_MAX; /* casts the rand output into float and the RAND_MAX into float so that a random floating point number between 0 and 1 is store$
    range = userInput2-userInput1; /* stores the difference between the two inputs in order for a random number to be created between the two bounds */
    randomNumber = (userInput1 + (random * range)); /* adds the random numberto the lower bound so that the final output is between the bounds */
    return randomNumber;
    mulligan.kyle, Mar 8, 2013
    1. Advertisements

  2. mulligan.kyle

    Joe Pfeiffer Guest

    It's because of the representation of a floating point number in the
    computer. Floats use what amounts to the binary equivalent of
    scientific notation, i.e.

    1.m * 2^e

    where 'm' is the significand and 'e' is the exponent. Without going into
    details, you've only 23 bits of significand; if you've got a small
    number then you'll have many of them to the right of the decimal point,
    and if you've got a large number you'll have many of them to the left of
    the decimal point and hence fewer to the right.
    Joe Pfeiffer, Mar 8, 2013
    1. Advertisements

  3. mulligan.kyle

    Noob Guest

    I suppose you've already skimmed the Wikipedia entry?

    Also, you might want to use "double" instead of "float".
    Noob, Mar 8, 2013
  4. mulligan.kyle

    Eric Sosman Guest

    That may only help a little, and perhaps not at all. Bear
    in mind that rand() can return at most 1+RAND_MAX distinct values,
    so any printed precision beyond log10(1+RAND_MAX) decimal digits
    is an illusion. RAND_MAX is often equal to INT_MAX which in turn
    is often 0x7FFFFFFF, for 9-and-change decimal digits; `float' can
    often handle 7-and-change (the Standard requires at least 6), so
    switching to `double' might gain only two decimal places.

    ... and perhaps not even that much. RAND_MAX can be as small
    as 32767, in which case a rand() value would be worth only four and
    a half decimal digits. In that case, switching from `float' to
    `double' would gain no precision at all -- even if you printed the
    value to lots and lots of places, most would be meaningless.
    Eric Sosman, Mar 8, 2013
  5. mulligan.kyle

    Noob Guest

    Au contraire, mon ami! ;-)

    Suppose he plans to generate random floating-point values between
    1e9 and 1e9+1. How well is that float gonna work for him? :-þ

    A related exercise is finding the smallest positive float value f
    for which f == f+1 (and understanding why, of course).

    I agree with the general feeling that floating-point numbers are
    a tricky devious bunch, and I stay away from 'em as much as I can.

    And this is where I drop the killer link to the article I've never
    had the patience/courage to read top-to-bottom.

    What Every Computer Scientist Should Know About Floating-Point Arithmetic

    Noob, Mar 8, 2013
  6. mulligan.kyle

    Ian Collins Guest

    I think you missed (as well as snipped!) Eric's point. This box
    (Solaris) has RAND_MAX = 32767, so switching to double would gain nothing.
    Ian Collins, Mar 8, 2013
  7. mulligan.kyle

    Eric Sosman Guest

    Actually, I think Noob has a point: If the desired values
    are of the form HugeConstant+TinyRandom, the greater precision
    of `double' will help postpone the inevitable losses.

    Of course, if HugeConstant is sufficiently large it will
    drown any TinyRandom, even in `double' or `long double' or
    `long long really really long double' (C21). Noob's point,
    then, is that extended precision can hide -- for a while --
    a bad choice of algorithm. It's folly to measure the distance
    to the Lesser Magellanic Cloud and then add a centimeter.
    Eric Sosman, Mar 9, 2013
  8. I guess the OP could use multiple invocations of rand() to get at as
    many bits of randomness that are required for the specified range...
    Johann Klammer, Mar 9, 2013
  9. mulligan.kyle

    Eric Sosman Guest

    When you combine N successive pseudo-random values to form
    a higher-precision result, you have to be concerned about the
    N-dimensional spectral characteristics of the original generator.
    For example, with a maximum-period linear congruential generator
    successive results alternate between odd and even values. If you
    combine these in pairs to get your lengthier result, you'll find
    that one of your result bits is always zero and another is always
    one (before scaling and whatever): two bits' worth of randomness
    have "disappeared."

    The Standard does not say what algorithm rand() should use
    (the example is only an example, not a prescription), so we don't
    know much about how N-apart values may be correlated. Even the
    statistical properties of 1-apart values are a mystery. If you
    need pseudo-random numbers with known "goodness," you'll need to
    code (or borrow) another RNG rather than relying on rand().
    Eric Sosman, Mar 9, 2013
  10. That's true for common modern implementations of the C standard.
    The seed argument to srand() is an unsigned int, which could be as
    narrow as 16 bits; there's no upper bound, but the widest I've seen
    is 64 bits.

    Still, there are times when it can make sense to generate more
    pseudo-random bits that the size of the internal state. For example,
    if you're plotting random points, having too few bits per sample can
    produce visible non-randomness. By using more bits, you can make
    the plotted points *look* more random, even if they're really not.
    (If you want something closer to true randomness, rand() is not
    the answer.)
    Keith Thompson, Mar 10, 2013
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.