Random Numbers ...
Lawrence Crowl
crowl at cs.rochester.edu
Fri Feb 26 08:39:33 AEST 1988
In article <5555 at cit-vax.Caltech.Edu> wen-king at cit-vlsi.UUCP
(Wen-King Su) writes:
>In article <7097 at sol.ARPA> crowl at cs.rochester.edu (Lawrence Crowl) writes:
><#define NEGABS( i ) ((i) > 0 ? -(i) : (i))
>>short rand16mod( modulus )
>< short modulus ;
>> {
>< seed16 = (short)(seed16 * 25173) + 13849 ;
>> return (short)NEGABS(seed16) / (short)(-32768 / modulus) ;
> ^^^^^^^^^^^^^^^^^^^^^
>Don't do this. Now you have a random number source that does not have
>an uniform distribution; both '0' and MAX_NEGATIVE occur at half the
>frequency as the other numbers. Use unsigned integers instead.
Since this was developed for a language providing only signed integers, the
use of unsigned numbers did not occur to me. The asymmetry with reguards to
0 and MAX_NEGATIVE are lost in the noise since the codes purpose was speed,
not extreme quality. The use of MAX_NEGATIVE provides the largest signed
power of two. I have fixed this since it costs little. (Given the loss of
inlining brought about by the loop introduced to fix the following problem.)
>Even if the random source is uniform over a range, say R, you can't expect
>the the result of a simple division to yield another uniform distribution
>unless R is a multiple of the divisor. For example, suppose the random
>source has a range of 0-7, and the divisor happens to be 3 (so that you get
>the numbers 0, 1, and 2 randomly).
If you look carefully at my old code, you will find that it uniformly
generates numbers in the range 0 .. modulus-1. Unfortunately, it also
occasionally generates the value modulus. This is not just a distribution
problem, it is an outright bug.
Taking Wen-King Su suggestions, I have redone the previous posting and
provide the result here. Please throw out the old version and forget I ever
posted it! The new code takes 60 micro-seconds for the 16-bit version and
150 micro-seconds for the 32-bit version on a Sun 2/170.
/*-------------------------------------------------------------------- random.c
This program contains a linear congruential pseudo-random number generator.
Each random number generation takes a parameter, modulus, and returns a
pseudo-random number in the range 0 ... modulus-1. The pseudo-random number
is taken from the high-order bits of the seed.
This file contains two versions of the generator, one for 16-bit arithmetic,
and one for 32-bit arithmetic.
Lawrence Crowl
University of Rochester
Computer Science Department
Rochester, New York, 14627
*/
/*-------------------------------------------------------------- 16-bit version
This version assumes that shorts are 16 bits. This allows the code to run
on machines with 32-bit ints but 16-bit hardware, such as the 68000. The
extensive casting allows reasonable compilers to generate 16-bit multiply
instructions.
The coefficients for the generator are from Peter Grogono, "Programming in
Pascal", Section 4.5, Addison-Wesley Publishing Company, 1978. I do not
know if these coefficients have been tested.
*/
static unsigned short seed16 ;
void rand16seed( seed )
unsigned short seed ;
{
seed16 = seed ;
}
short rand16mod( modulus )
register unsigned short modulus ;
{
register unsigned short result, reg_seed ;
reg_seed = seed16 ;
do {
reg_seed = (unsigned short)(reg_seed * 25173) + 13849 ;
result = (unsigned short)(reg_seed >> 1)
/ (unsigned short)(32767 / modulus) ;
/* result = reg_seed / (unsigned short)(65535 / modulus) ; */
/* the Sun compiler thinks 65535 needs long division */
}
while ( result >= modulus ) ;
seed16 = reg_seed ;
return result ;
}
/*-------------------------------------------------------------- 32-bit version
This version assumes that ints are 32 bits.
The coefficients for the generator are from David Dantowitz in article
<11972 at brl-adm.ARPA> of the comp.lang.c news group. I do not know if
these coefficients have been tested.
*/
static unsigned int seed32 ;
void rand32seed( seed )
unsigned int seed ;
{
seed32 = seed ;
}
int rand32mod( modulus )
register unsigned int modulus ;
{
register unsigned int result, reg_seed ;
reg_seed = seed32 ;
do {
reg_seed = (reg_seed * 1103515245) + 12345 ;
result = reg_seed / (4294967295 / modulus) ;
}
while ( result >= modulus ) ;
seed32 = reg_seed ;
return result ;
}
/*------------------------------------------------- demonstration program
This is not a test program. For test procedures, see Donald E. Knuth,
"The Art of Computer Programming", Chaper 3, Volume 2, Second Edition,
Addison-Wesley Publishing Company, 1981
*/
#include <stdio.h>
#include <sys/time.h>
#define ITERATIONS 100000
void main( argc, argv )
int argc ;
char **argv ;
{
int i ;
struct timeval t1, t2, t3 ;
long d1, d2 ;
float di ;
int samples = atoi( argv[ 1 ] ) ;
int modulus = atoi( argv[ 2 ] ) ;
/* demonstrate 16-bit version */
for ( i = 0 ; i < samples ; i++ )
(void)printf( " %d", rand16mod( modulus ) ) ;
printf( "\n" ) ;
/* time 16-bit version */
gettimeofday( &t1, (struct timezone *)NULL ) ;
for ( i = 0 ; i < ITERATIONS ; i++ )
;
gettimeofday( &t2, (struct timezone *)NULL ) ;
for ( i = 0 ; i < ITERATIONS ; i++ )
(void)rand16mod( modulus ) ;
gettimeofday( &t3, (struct timezone *)NULL ) ;
d1 = (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec) ;
d2 = (t3.tv_sec - t2.tv_sec) * 1000000 + (t3.tv_usec - t2.tv_usec) ;
di = (d2 - d1) / (float) ITERATIONS ;
(void)printf( "microseconds 16-bit, null %d body %d iteration %f\n",
d1, d2, di ) ;
/* demonstrate 32-bit version */
for ( i = 0 ; i < samples ; i++ )
(void)printf( " %d", rand32mod( modulus ) ) ;
printf( "\n" ) ;
/* time 32-bit version */
gettimeofday( &t1, (struct timezone *)NULL ) ;
for ( i = 0 ; i < ITERATIONS ; i++ )
;
gettimeofday( &t2, (struct timezone *)NULL ) ;
for ( i = 0 ; i < ITERATIONS ; i++ )
(void)rand32mod( modulus ) ;
gettimeofday( &t3, (struct timezone *)NULL ) ;
d1 = (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec) ;
d2 = (t3.tv_sec - t2.tv_sec) * 1000000 + (t3.tv_usec - t2.tv_usec) ;
di = (d2 - d1) / (float) ITERATIONS ;
(void)printf( "microseconds 32-bit, null %d body %d iteration %f\n",
d1, d2, di ) ;
}
--
Lawrence Crowl 716-275-9499 University of Rochester
crowl at cs.rochester.edu Computer Science Department
...!{allegra,decvax,rutgers}!rochester!crowl Rochester, New York, 14627
More information about the Comp.lang.c
mailing list