[net.bugs.4bsd] using rand portably

mark (03/28/83)

Since the point of the macro I posted was to be portable across UNIX
implementations (it certainly wasn't to generate wonderful random
numbers on 4.1BSD - it should right shift 16 bits to do that, but
this would lose portability; it turns out it does generate reasonable
random numbers on 4.1), I'd like to share some improvements and
corrections to it from Tom Duff:

The macro

#define	randint(n) ( ((long) rand() & 0177777) * n / 0177777)

has a bug.  When rand() generates a number with 16 low-order 1-bits,
which it does once in 65536 calls, on average,  the result of the macro
will be n, which is not in the range [0,n-1].  I believe that the
following will work, however:

#define	randint(n) (int)(((long)rand()&077777)*(n)/0100000L)

This will probably work on pdp11s, vaxs, SUNs and other 68000s and
just about any other binary machine whose word length is 16 bits or more.

I also fixed four other bugs.  First, some versions of rand produce
15 bit results, so the mask 0177777 is one bit too big.  Second,
your randint would fail on the call
	randint(n+1)
because of some missing parentheses.
Third, the type of the result should probably be (int), not (long).
Fourth, on 16 bit machines,
0177777 (and 0100000, which replaces it in my version) are negative
numbers, and need to have an `L' appended to come out positive.

On n bit machines, integer constants are implicitly made long
if they are decimal and have more than n-1 bits precision, or
if they are octal or hexadecimal and have more than n bits precision.
0177777 has only 16 bits precision, and therefore on a 16 bit machine
is short and therefore -1.  Unless, of course you're on a
ones complement machine, in which case it's -0.  And, of course on
signed-magnitude machines, the value is -32767.

If you wanted it to work on all machines, independent of number
representation, you should probably rewrite it as:

#define	randint(n) (rand()%(P-1)*(n)/P)

where P is the largest representable positive integer.

In all fairness, only one of my four additional bugs makes a
difference on a VAX.  But if you claim portability, you should
be able to back it up.  The worst portability problems (at least
in UNIX code, where you can mostly depend on system software
compatibility) arise from data representation problems.