Random Numbers

Joachim Durchholz joachim.durchholz at munich.netsurf.de
Thu May 20 19:45:33 UTC 1999


"Michael S. Klein" wrote:
> 
> > On scaling:
> > A single byte can be interpreted as a number between 0 and 255 (then
> > it's called "unsigned") or between -128 and 127 (then it's called
> > "signed").
> > To scale such a byte to a number between 0.0 and 1.0, just divide
> > the byte value by the range of numbers expressible with it (which is
> > 256 in both cases: you have 256 values to select from).
> 
> Common mistake... Divide by 255, not 256, otherwise you dont get full
> range of 0 thru 1.  Don't be tempted to 'optimize' by doing bit-shift
> division.

That was intentional.
You usually want numbers in the range including 0.0 and excluding 1.0.
Most (if not all) standard random number generators with a
floating-point output work that way. This is no surprise, as one usually
doesn't want 1.0 as a result.

Another hint: It's usually not very interesting to use floating-point
results. You usually want some fixed sets of integers. Conversion to and
from floating-point representation risks losing bits due to round-off
errors (not if you're dividing by a power of two, but even then a bug in
some floating-point library or in the FPU of the processor can foul
things up).
So what I usually do if I have to write a random generator from scratch
is the following:
1) Get me a good source random seed. User input, the current
millisecond, whatever.
2) Write a random number generator. Depending on the application, it
will be a simple multiply-divide-remainder one, or a cryptographically
secure one. I make sure that the random numbers have enough bits to
satisfy the application (just using two consecutive outputs to generate
a double-size random number won't do, at least not if I'm serious about
the quality of the random numbers - I like to be serious, so I'll
probably do it even if I'm just doing a simple game).
3) Write a function that takes two bounds and scales my random numbers
to the desired range. This will be equivalent to conversion to
floating-point and conversion back, but it will have the additional
advantage that I don't even have to think about round-off errors.
Something like
  Random>>rangedFrom: To:
Of course you'd have to look out for fencepost errors (an inherent
danger of integer ranges).
One additional wrinkle: Scaling will divide the random number output
into a set of intervals. As the original numbers are integers, the the
intervals may differ by 1 in width. This is not a noticeable problem if
you have a large number of bits in your random numbers and small result
ranges. It can become a problem if you have, say, an 8-bit random number
generator and 120 categories: You'll get 16 intervals with 3 numbers in
them and 240 intervals with 2 numbers in them. If this is of concern to
you, you'll have to keep generating random numbers until you get one
that's below 240, and divide by 240. If you have a good generator with a
long period, this can take a while in the worst case. Off the top of my
head, I don't know of an algorithm that would solve this problem.

Regards,
Joachim
-- 
Please don't send unsolicited ads.





More information about the Squeak-dev mailing list