Path: utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!hao!gatech!bbn!rochester!crowl From: crowl@cs.rochester.edu (Lawrence Crowl) Newsgroups: comp.lang.c Subject: Re: Random Numbers ... Message-ID: <7097@sol.ARPA> Date: 24 Feb 88 17:26:52 GMT References: <11972@brl-adm.ARPA> Reply-To: crowl@cs.rochester.edu (Lawrence Crowl) Organization: U of Rochester, CS Dept, Rochester, NY Lines: 157 Most of my need for random numbers comes in the form of a random integer modulo some application specific value. A lot of random number generators return either a floating value, or some integer within the complete range of integers, which I must then hack at to get it within the range of integers that I want. Rather than do this all the time, I wrote a random number generator which accepts the modulus and does the modulo calculations internally. Here is the result of that effort. On a Sun 2/170, the 16-bit version takes 54 micro- seconds and the 32-bit version takes 158 micro-seconds. /*-------------------------------------------------------------------- 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. Because twos complement integers have more negative values than positive, this generator uses the negative of the absolute value for some operations. If the modulus is constant, an macro implementation of this generator will eliminate a division. In addition, the modulus parameter is evaluated only once, so it will have no undue side effects. This file contains two versions of the generator, one for 16-bit twos complement arithmentic, and one for 32-bit twos complement arithmetic. Lawrence Crowl University of Rochester Computer Science Department Rochester, New York, 14627 */ /*----------------------------------------------------------------------- tools Note that since the parameter to NEGABS is evaluated more than once, the actual argument should have no side effects. */ #define NEGABS( i ) ((i) > 0 ? -(i) : (i)) /*-------------------------------------------------------------- 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 short seed16 ; void rand16seed( seed ) short seed ; { seed16 = seed ; } short rand16mod( modulus ) short modulus ; { seed16 = (short)(seed16 * 25173) + 13849 ; return (short)NEGABS(seed16) / (short)(-32768 / modulus) ; } /*-------------------------------------------------------------- 32-bit version This version assumes that ints are 32 bits. The coefficients for the generator are from David Dantowitz in article <11972@brl-adm.ARPA> of the comp.lang.c news group. I do not know if these coefficients have been tested. */ static int seed32 ; void rand32seed( seed ) int seed ; { seed32 = seed ; } int rand32mod( modulus ) int modulus ; { seed32 = (seed32 * 1103515245) + 13849 ; return NEGABS(seed32) / (-2147483648 / modulus) ; } /*------------------------------------------------- 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 #include #define ITERATIONS 1000000 void main( ) { int i, j ; struct timeval t1, t2, t3 ; long d1, d2 ; float di ; /* demonstrate 16-bit version */ for ( i = 4 ; i <= 8 ; i++ ) { for ( j = 0 ; j <= 20 ; j++ ) (void)printf( " %d", rand16mod( i ) ) ; 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( 32 ) ; 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 = 4 ; i <= 8 ; i++ ) { for ( j = 0 ; j <= 20 ; j++ ) (void)printf( " %d", rand32mod( i ) ) ; 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( 32 ) ; 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@cs.rochester.edu Computer Science Department ...!{allegra,decvax,rutgers}!rochester!crowl Rochester, New York, 14627