From: Martin Str|mberg Message-Id: <199901202005.VAA21625@father.ludd.luth.se> Subject: rand48 patch 2 To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS) Date: Wed, 20 Jan 1999 21:05:56 +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() to libc. I've received almost no feedback (one comment from Eli), so I'm a little hesitant if this should be added yet. Test it please. Right, MartinS diff -ruN include.org/stdlib.h include/stdlib.h --- include.org/stdlib.h Sat Jul 25 18:58:46 1998 +++ include/stdlib.h Wed Jan 6 20:56:42 1999 @@ -83,18 +83,27 @@ long double _atold(const char *_s); long long atoll(const char *_s); void cfree(void *_ptr); +double drand48(void); char * ecvtbuf(double _val, int _nd, int *_dp, int *_sn, char *_bf); char * ecvt(double _val, int _nd, int *_dp, int *_sn); +double erand48(unsigned short state[3]); char * fcvtbuf(double _val, int _nd, int *_dp, int *_sn, char *_bf); char * fcvt(double _val, int _nd, int *_dp, int *_sn); char * gcvt(double _val, int _nd, char *_buf); char * getpass(const char *_prompt); int getlongpass(const char *_prompt, char *_buffer, int _max_len); char * itoa(int value, char *buffer, int radix); +long jrand48(unsigned short state[3]); long long llabs(long long _i); lldiv_t lldiv(long long _numer, long long _denom); +void lcong48(unsigned short param[7]); +unsigned long lrand48(void); +long mrand48(void); +unsigned long nrand48(unsigned short state[3]); int putenv(const char *_val); +unsigned short *seed48(unsigned short state_seed[3]); int setenv(const char *_var, const char *_val, int _replace); +void srand48(long seedval); int stackavail(void); long double _strtold(const char *_s, char **_endptr); long long strtoll(const char *_s, char **_endptr, int _base); diff -ruN 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 -ruN 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 Mon Jan 11 09:20:40 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 -ruN 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 Sun Jan 10 16:56:16 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 +@var{seed}. The low order 16 bits are set to the arbitrary value +0x330e. + +@code{seed48} sets the internal state according to the argument +@var{state_seed} (@var{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 @var{param[0-2]}, a to +@var{param[3-5]} (@var{param[0]} and @var{param[3]} are least +significant) and c to @var{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