aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
authorRichard Kistruck2009-01-20 15:59:32 +0000
committerRichard Kistruck2009-01-20 15:59:32 +0000
commite486078a79edd55a290e4087ee92c114fa301e0d (patch)
tree0ba1b8449ce6add9ab322870846f5f36a0f1d14a /mps/code
parent4fc1ea19fbf43ab263c604f26870eb935399c44d (diff)
downloademacs-e486078a79edd55a290e4087ee92c114fa301e0d.tar.gz
emacs-e486078a79edd55a290e4087ee92c114fa301e0d.zip
Mps br.timing: testlib randomize() was wrong (simply discarding the first 0..32000 values is a throughly defective way to seed the generator). correct it to simply use timestamp (modulo m) as the initial seed, and then iterate 10 times.
rnd(): add notes, and create rnd_verify() to confirm implementation is correct. Copied from Perforce Change: 167181 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/testlib.c99
1 files changed, 87 insertions, 12 deletions
diff --git a/mps/code/testlib.c b/mps/code/testlib.c
index b22ed52bd2c..5c92969d2e0 100644
--- a/mps/code/testlib.c
+++ b/mps/code/testlib.c
@@ -36,21 +36,73 @@ struct itimerspec; /* stop complaints from time.h */
36 * 36 *
37 * I nabbed it from "ML for the Working Programmer", originally from: 37 * I nabbed it from "ML for the Working Programmer", originally from:
38 * Stephen K Park & Keith W Miller (1988). Random number generators: 38 * Stephen K Park & Keith W Miller (1988). Random number generators:
39 * good one are to find. Communications of the ACM, 31:1192-1201. 39 * good ones are hard to find. Communications of the ACM, 31:1192-1201.
40 *
41 * This is a 'full-period' generator: all values from [1..(mod-1)]
42 * are returned once, and then the generator cycles round again.
43 * (The value 0 is not part of the cycle and is never returned). That
44 * means the period = mod-1, ie. 2147483646.
45 *
46 * This "x 16807 mod 2^31-1" generator has been very well studied.
47 * It is not the 'best' (most random) simple generator, but it is
48 * free of all vices we might care about for this application, so
49 * we'll keep it simple and stick with this, thanks.
50 *
51 * There are faster implementations of this generator, summarised
52 * briefly here:
53 * - L. Schrage (1979 & 1983) showed how to do all the calculations
54 * within 32-bit integers. See also Numerical recipes in C.
55 * - David Carta (1990) showed how to also eliminate division.
40 */ 56 */
41 57
58static unsigned long seed = 1;
59/* 2^31 - 1 == (1UL<<31) - 1 == 2147483647 */
60#define RND_MOD_2_31_1 2147483647
61#define RND_MOD_2_31_1_FLOAT 2147483647.0
42unsigned long rnd(void) 62unsigned long rnd(void)
43{ 63{
44 static unsigned long seed = 1;
45 double s; 64 double s;
46 65
47 s = seed; 66 s = seed;
48 s *= 16807.0; 67 s *= 16807.0;
49 s = fmod(s, 2147483647.0); /* 2^31 - 1 */ 68 s = fmod(s, RND_MOD_2_31_1_FLOAT); /* 2^31 - 1 */
50 seed = (unsigned long)s; 69 seed = (unsigned long)s;
51 return seed; 70 return seed;
71 /* Have you modified this code? Run rnd_verify() please! RHSK */
52} 72}
53 73
74/* rnd_verify -- verify that rnd() returns the correct results */
75static void rnd_verify(void)
76{
77 unsigned long orig_seed = seed;
78 unsigned long i;
79
80 /* This test is from:
81 * Stephen K Park & Keith W Miller (1988). Random number generators:
82 * good ones are hard to find. Communications of the ACM, 31:1192-1201.
83 * Note: The Park-Miller paper uses 1-based indices.
84 */
85 i = 1;
86 seed = 1;
87 for(i = 2; i < 10001; i += 1) {
88 (void)rnd();
89 }
90 Insist(i == 10001);
91 Insist(rnd() == 1043618065);
92
93 /* from Robin Whittle's compendium at
94 * http://www.firstpr.com.au/dsp/rand31/
95 * Observe wrap-around after 'full-period' (which excludes 0).
96 * Note: uses 0-based indices, ie. rnd_0 = 1, rnd_1 = 16807, ...
97 */
98 i = 2147483645;
99 seed = 1407677000;
100 i += 1;
101 Insist(i == (1UL<<31) - 2 ); /* 'full-period' excludes 0 */
102 Insist(rnd() == 1); /* wrap-around */
103
104 seed = orig_seed;
105}
54 106
55/* rnd_addr -- a random address generator 107/* rnd_addr -- a random address generator
56 * 108 *
@@ -75,19 +127,42 @@ mps_addr_t rnd_addr(void)
75 127
76void randomize(int argc, char **argv) 128void randomize(int argc, char **argv)
77{ 129{
78 int i, k, n; 130 int n;
131 unsigned long seed0;
132 int i;
79 133
80 if (argc > 1) { 134 if (argc > 1) {
81 n = sscanf(argv[1], "%d", &k); 135 n = sscanf(argv[1], "%lu", &seed0);
82 die((n == 1) ? MPS_RES_OK : MPS_RES_FAIL, "randomize"); 136 Insist(n == 1);
137 printf("randomize(): resetting initial seed to: %lu.\n", seed0);
138 rnd_verify(); /* good to verify occasionally: slip it in here */
83 } else { 139 } else {
84 k = time(NULL) % 32000; 140 /* time_t uses an arbitrary encoding, but hopefully the low order */
85 printf("Randomizing %d times.\n", k); 141 /* 31 bits will have at least one bit changed from run to run. */
142 seed0 = 1 + time(NULL) % (RND_MOD_2_31_1 - 1);
143 printf("randomize(): choosing initial seed: %lu.\n", seed0);
86 } 144 }
87 145
88 /* Randomize the random number generator a bit. */ 146 Insist(seed0 < RND_MOD_2_31_1); /* 2^31 - 1 */
89 for (i = k; i > 0; --i) 147 Insist(seed0 != 0);
90 rnd(); 148 seed = seed0;
149
150 /* The 'random' seed is taken from time(), which may simply be a
151 * count of seconds: therefore successive runs may start with
152 * nearby seeds, possibly differing only by 1. So the first value
153 * returned by rnd() may differ by only 16807. It is conceivable
154 * that some tests might be able to 'spot' this pattern (for
155 * example: by using the first rnd() value, mod 100M and rounded
156 * to multiple of 128K, as arena size).
157 *
158 * So to mix it up a bit, we do a few iterations now. How many?
159 * Very roughly, 16807^2 is of the same order as 2^31, so two
160 * iterations would make the characteristic difference similar to
161 * the period. Hey, let's go wild and do 10.
162 */
163 for(i = 0; i < 10; i += 1) {
164 (void)rnd();
165 }
91} 166}
92 167
93 168
@@ -146,7 +221,7 @@ void cdie(int res, const char *s)
146 221
147/* C. COPYRIGHT AND LICENSE 222/* C. COPYRIGHT AND LICENSE
148 * 223 *
149 * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>. 224 * Copyright (C) 2001-2002, 2008 Ravenbrook Limited <http://www.ravenbrook.com/>.
150 * All rights reserved. This is an open source license. Contact 225 * All rights reserved. This is an open source license. Contact
151 * Ravenbrook for commercial licensing options. 226 * Ravenbrook for commercial licensing options.
152 * 227 *