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

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

1. ### mulligan.kyleGuest

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
(the range between these bounds is 13)

enter lower and upper limits separated by a comma: 1234567,1234575
(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.

-Kyle

#include<stdio.h>
#include<stdlib.h>

float randomBetween(float, float);

main()
{
float userInput1,
userInput2,
randomNumber;
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,
randomNumber,
range;
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

2. ### Joe PfeifferGuest

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

3. ### NoobGuest

I suppose you've already skimmed the Wikipedia entry?
https://en.wikipedia.org/wiki/Floating_point

Also, you might want to use "double" instead of "float".

Noob, Mar 8, 2013
4. ### Eric SosmanGuest

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. ### NoobGuest

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

What Every Computer Scientist Should Know About Floating-Point Arithmetic
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Regards.

Noob, Mar 8, 2013
6. ### Ian CollinsGuest

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. ### Eric SosmanGuest

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. ### Johann KlammerGuest

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. ### Eric SosmanGuest

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. ### Keith ThompsonGuest

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