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 * 3. 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/param.h> 40 #include <sys/sysctl.h> 41 #include <stdlib.h> 42 #include "un-namespace.h" 43 44 #ifdef TEST 45 #include <stdio.h> 46 #endif /* TEST */ 47 48 static int 49 do_rand(unsigned long *ctx) 50 { 51 /* 52 * Compute x = (7^5 * x) mod (2^31 - 1) 53 * without overflowing 31 bits: 54 * (2^31 - 1) = 127773 * (7^5) + 2836 55 * From "Random number generators: good ones are hard to find", 56 * Park and Miller, Communications of the ACM, vol. 31, no. 10, 57 * October 1988, p. 1195. 58 */ 59 long hi, lo, x; 60 61 /* Transform to [1, 0x7ffffffe] range. */ 62 x = (*ctx % 0x7ffffffe) + 1; 63 hi = x / 127773; 64 lo = x % 127773; 65 x = 16807 * lo - 2836 * hi; 66 if (x < 0) 67 x += 0x7fffffff; 68 /* Transform to [0, 0x7ffffffd] range. */ 69 x--; 70 *ctx = x; 71 return (x); 72 } 73 74 75 int 76 rand_r(unsigned *ctx) 77 { 78 u_long val; 79 int r; 80 81 val = *ctx; 82 r = do_rand(&val); 83 *ctx = (unsigned)val; 84 return (r); 85 } 86 87 88 static u_long next = 1; 89 90 int 91 rand(void) 92 { 93 return (do_rand(&next)); 94 } 95 96 void 97 srand(unsigned seed) 98 { 99 next = seed; 100 } 101 102 103 /* 104 * sranddev: 105 * 106 * Many programs choose the seed value in a totally predictable manner. 107 * This often causes problems. We seed the generator using pseudo-random 108 * data from the kernel. 109 */ 110 void 111 sranddev(void) 112 { 113 int mib[2]; 114 size_t len; 115 116 len = sizeof(next); 117 118 mib[0] = CTL_KERN; 119 mib[1] = KERN_ARND; 120 sysctl(mib, 2, (void *)&next, &len, NULL, 0); 121 } 122 123 124 #ifdef TEST 125 126 main() 127 { 128 int i; 129 unsigned myseed; 130 131 printf("seeding rand with 0x19610910: \n"); 132 srand(0x19610910); 133 134 printf("generating three pseudo-random numbers:\n"); 135 for (i = 0; i < 3; i++) 136 { 137 printf("next random number = %d\n", rand()); 138 } 139 140 printf("generating the same sequence with rand_r:\n"); 141 myseed = 0x19610910; 142 for (i = 0; i < 3; i++) 143 { 144 printf("next random number = %d\n", rand_r(&myseed)); 145 } 146 147 return 0; 148 } 149 150 #endif /* TEST */ 151 152