/ stdlib / FreeBSD / rand.c
rand.c
  1  /*-
  2   * Copyright (c) 1990, 1993
  3   *	The Regents of the University of California.  All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   * 4. Neither the name of the University nor the names of its contributors
 14   *    may be used to endorse or promote products derived from this software
 15   *    without specific prior written permission.
 16   *
 17   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 18   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 21   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27   * SUCH DAMAGE.
 28   *
 29   * Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>.
 30   */
 31  
 32  #if defined(LIBC_SCCS) && !defined(lint)
 33  static char sccsid[] = "@(#)rand.c	8.1 (Berkeley) 6/14/93";
 34  #endif /* LIBC_SCCS and not lint */
 35  #include <sys/cdefs.h>
 36  __FBSDID("$FreeBSD$");
 37  
 38  #include "namespace.h"
 39  #include <sys/time.h>          /* for sranddev() */
 40  #include <sys/types.h>
 41  #include <fcntl.h>             /* for sranddev() */
 42  #include <stdlib.h>
 43  #include <unistd.h>            /* for sranddev() */
 44  #include "un-namespace.h"
 45  
 46  #ifdef TEST
 47  #include <stdio.h>
 48  #endif /* TEST */
 49  
 50  static int
 51  do_rand(unsigned long *ctx)
 52  {
 53  #ifdef  USE_WEAK_SEEDING
 54  /*
 55   * Historic implementation compatibility.
 56   * The random sequences do not vary much with the seed,
 57   * even with overflowing.
 58   */
 59  	return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
 60  #else   /* !USE_WEAK_SEEDING */
 61  /*
 62   * Compute x = (7^5 * x) mod (2^31 - 1)
 63   * without overflowing 31 bits:
 64   *      (2^31 - 1) = 127773 * (7^5) + 2836
 65   * From "Random number generators: good ones are hard to find",
 66   * Park and Miller, Communications of the ACM, vol. 31, no. 10,
 67   * October 1988, p. 1195.
 68   */
 69  	long hi, lo, x;
 70  
 71  	/* Can't be initialized with 0, so use another value. */
 72  	if (*ctx == 0)
 73  		*ctx = 123459876;
 74  	hi = *ctx / 127773;
 75  	lo = *ctx % 127773;
 76  	x = 16807 * lo - 2836 * hi;
 77  	if (x < 0)
 78  		x += 0x7fffffff;
 79  	return ((*ctx = x) % ((u_long)RAND_MAX + 1));
 80  #endif  /* !USE_WEAK_SEEDING */
 81  }
 82  
 83  
 84  int
 85  rand_r(unsigned int *ctx)
 86  {
 87  	u_long val = (u_long) *ctx;
 88  	int r = do_rand(&val);
 89  
 90  	*ctx = (unsigned int) val;
 91  	return (r);
 92  }
 93  
 94  
 95  static u_long next = 1;
 96  
 97  int
 98  rand()
 99  {
100  	return (do_rand(&next));
101  }
102  
103  void
104  srand(seed)
105  u_int seed;
106  {
107  	next = seed;
108  }
109  
110  
111  /*
112   * sranddev:
113   *
114   * Many programs choose the seed value in a totally predictable manner.
115   * This often causes problems.  We seed the generator using the much more
116   * secure random(4) interface.
117   */
118  void
119  sranddev(void)
120  {
121  	int fd, done;
122  
123  	done = 0;
124  	fd = _open("/dev/random", O_RDONLY | O_CLOEXEC, 0);
125  	if (fd >= 0) {
126  		if (_read(fd, (void *) &next, sizeof(next)) == sizeof(next))
127  			done = 1;
128  		_close(fd);
129  	}
130  
131  	if (!done) {
132  		struct timeval tv;
133  
134  		gettimeofday(&tv, NULL);
135  		srand((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec);
136  	}
137  }
138  
139  
140  #ifdef TEST
141  
142  main()
143  {
144      int i;
145      unsigned myseed;
146  
147      printf("seeding rand with 0x19610910: \n");
148      srand(0x19610910);
149  
150      printf("generating three pseudo-random numbers:\n");
151      for (i = 0; i < 3; i++)
152      {
153  	printf("next random number = %d\n", rand());
154      }
155  
156      printf("generating the same sequence with rand_r:\n");
157      myseed = 0x19610910;
158      for (i = 0; i < 3; i++)
159      {
160  	printf("next random number = %d\n", rand_r(&myseed));
161      }
162  
163      return 0;
164  }
165  
166  #endif /* TEST */
167