From: Martin Str|mberg Message-Id: <199901091259.NAA01314@sister.ludd.luth.se> Subject: rand48 for libc To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS) Date: Sat, 9 Jan 1999 13:59:28 +0100 (MET) X-Mailer: ELM [version 2.4ME+ PL15 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Reply-To: djgpp-workers AT delorie DOT com Here's the patch to add *rand48() functions to libc. This time with documentation. Holmboe, Symphony 7, MartinS diff -rNu src.org/libc/compat/stdlib/makefile src/libc/compat/stdlib/makefile --- src.org/libc/compat/stdlib/makefile Sat Jul 25 18:58:44 1998 +++ src/libc/compat/stdlib/makefile Wed Jan 6 20:05:08 1999 @@ -20,6 +20,7 @@ SRC += fcvtbuf.c SRC += fcvt.c SRC += gcvt.c +SRC += rand48.c include $(TOP)/../makefile.inc diff -rNu src.org/libc/compat/stdlib/rand48.c src/libc/compat/stdlib/rand48.c --- src.org/libc/compat/stdlib/rand48.c Thu Jan 1 00:00:00 1970 +++ src/libc/compat/stdlib/rand48.c Sat Jan 9 13:29:34 1999 @@ -0,0 +1,186 @@ +/* + * File rand48.c. + * + * Copyright (C) 1999 Martin Strömberg . + * + * This software may be used freely so long as this copyright notice is + * left intact. There is no warranty on this software. + * + */ + +#include "stdlib.h" + +#define RAND48_MULT0 (0xe66d) +#define RAND48_MULT1 (0xdeec) +#define RAND48_MULT2 (0x0005) +#define RAND48_ADD (0x000b) + +static unsigned short internal_state[3] = {1, 0, 0}; +static unsigned short multiplier0 = RAND48_MULT0; +static unsigned short multiplier1 = RAND48_MULT1; +static unsigned short multiplier2 = RAND48_MULT2; +static unsigned short additiver = RAND48_ADD; + +static void next( + unsigned short state[] + ) +{ + unsigned short new_state[3]; + unsigned long tmp; + + tmp = state[0] * multiplier0 + additiver; + new_state[0] = (unsigned short)(tmp & 0xffff); + + tmp = (tmp >> 8*sizeof(unsigned short)) + + state[0] * multiplier1 + + state[1] * multiplier0; + new_state[1] = (unsigned short)(tmp & 0xffff); + + tmp = (tmp >> 8*sizeof(unsigned short)) + + state[0] * multiplier2 + + state[1] * multiplier1 + + state[2] * multiplier0; + new_state[2] = (unsigned short)(tmp & 0xffff); + + memcpy(state, new_state, 3*sizeof(unsigned short)); +} + +double drand48(void) +{ + return(erand48(internal_state)); +} + +double erand48( + unsigned short state[3] + ) +{ + int i; /* Counter. */ + double pot = 0.5; /* A potential of 0.5. */ + double result = 0.0; + + next(state); + + for(i = 0; i < 8*sizeof(unsigned short); i++) + { + if( (state[2] << i) & 0x8000 ) + { + result += pot; + } + pot /= 2.0; + if( (state[1] << i) & 0x8000 ) + { + result += pot; + } + pot /= 2.0; + if( (state[0] << i) & 0x8000 ) + { + result += pot; + } + pot /= 2.0; + } + + return(result); + +} + + +unsigned long lrand48(void) +{ + return(nrand48(internal_state)); +} + + +unsigned long nrand48( + unsigned short state[3] + ) +{ + + next(state); + return( ((unsigned long)state[2]) * 0x8000 + + ( ((unsigned long)state[1]) >> 1 ) + ); + +} + + +long mrand48(void) +{ + return(jrand48(internal_state)); +} + + +long jrand48( + unsigned short state[3] + ) +{ + + next(state); + if( (state[2] & 0x8000) ) + { + return( -1.0 * ((long)(state[2] & 0x7fff)) * 0x10000 + ((unsigned long)state[1]) ); + } + else + { + return( ((long)(state[2] & 0x7fff)) * 0x10000 + ((unsigned long)state[1]) ); + } + +} + +void srand48( + long seedval + ) +{ + + /* Restore default multipliers and additiver. */ + multiplier0 = RAND48_MULT0; + multiplier1 = RAND48_MULT1; + multiplier2 = RAND48_MULT2; + additiver = RAND48_ADD; + + /* Setup the new state. */ + internal_state[0] = 0x330e; + internal_state[1] = (seedval & 0xffff); + internal_state[2] = ( (seedval >> 16) & 0xffff); + +} + +unsigned short *seed48( + unsigned short state_seed[3] + ) +{ + static unsigned short old_state[3]; + + /* Restore default multipliers and additiver. */ + multiplier0 = RAND48_MULT0; + multiplier1 = RAND48_MULT1; + multiplier2 = RAND48_MULT2; + additiver = RAND48_ADD; + + /* Remember old state. */ + memcpy(old_state, internal_state, 3*sizeof(unsigned short)); + + /* Setup the new state. */ + memcpy(internal_state, state_seed, 3*sizeof(unsigned short)); + + return(old_state); +} + +void lcong48( + unsigned short param[7] + ) +{ + + /* Set the state. */ + internal_state[0] = param[0]; + internal_state[1] = param[1]; + internal_state[2] = param[2]; + + /* Set the multipilers. */ + multiplier0 = param[3]; + multiplier1 = param[4]; + multiplier2 = param[5]; + + /* Set the additiver. */ + additiver = param[6]; + +} diff -rNu src.org/libc/compat/stdlib/rand48.txh src/libc/compat/stdlib/rand48.txh --- src.org/libc/compat/stdlib/rand48.txh Thu Jan 1 00:00:00 1970 +++ src/libc/compat/stdlib/rand48.txh Thu Jan 7 09:39:36 1999 @@ -0,0 +1,80 @@ +@node rand48, random number +@subheading Syntax + +@example +#include + +double drand48(void); +double erand48(unsigned short state[3]); +unsigned long lrand48(void); +unsigned long nrand48(unsigned short state[3]); +long mrand48(void); +long jrand48(unsigned short state[3]); +void srand48(long seed); +unsigned short *seed48(unsigned short state_seed[3]); +void lcong48(unsigned short param[7]); +@end example + +@subheading Description + +This is the family of *rand48 functions. The basis for these functions +is the linear congruential formula X[n+1] = (a*X[n] + c) mod 2^48, n +>= 0. a = 0x5deece66d and c = 0xb at start and after a call to either +@code{srand48()} or @code{seed48()}. A call to @code{lcong48()} +changes a and c (and the internal state). + +@code{drand48()} and @code{erand48()} return @code{double}s uniformly +distributed in the interval [0.0, 1.0). + +@code{lrand48()} and @code{nrand48()} return @code{unsigned long}s +uniformly distributed in the interval [0, 2^31). + +@code{mrand48()} and @code{jrand48()} return @code{long}s uniformly +distributed in the interval [-2^31, 2^31). + +@code{erand48()}, @code{jrand48()} and @code{nrand48()} requires the +state of the random generator to be passed. + +@code{drand48()}, @code{lrand48()} and @code{mrand48()} uses an +internal state (common with all three functions) which should be +initialised with a call to one of the functions @code{srand48()}, +@code{seed48()} or @code{lcong48()}. + +@code{srand48()} sets the high order 32 bits to the argument +@code{seed}. The low order 16 bits are set to the arbitrary value +0x330e. + +@code{seed48()} sets the internal state according to the argument +@code{state_seed} (@code{state_seed[0]} is least significant). The +previous state of the random generator is saved in an internal +(static) buffer, to which a pointer is returned. + +@code{lcong48()} sets the internal state to @code{param[0-2]}, a to +@code{param[3-5]} (@code{param[0]} and @code{param[3]} are least +significant) and c to @code{param[6]}. + +@subheading Return Value + +A random number. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include +#include + +int main(void) +@{ + + srand48(time(NULL)); + printf("%.12f is a random number in [0.0, 1.0).\n", drand48()); + + exit(0); +@} + +@end example