~ubuntu-branches/ubuntu/precise/libdrm/precise-proposed

« back to all changes in this revision

Viewing changes to xf86drmRandom.c

Tags: 2.4.17-0ubuntu1
* Merge with Debian unstable, remaining changes:
  + control, rules, libdrm-nouveau1.symbols: Enable libdrm_nouveau.
* Update libdrm-nouveau1.symbols and shlibs.
* Drop 02_silent_master.diff, applied upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* xf86drmRandom.c -- "Minimal Standard" PRNG Implementation
 
2
 * Created: Mon Apr 19 08:28:13 1999 by faith@precisioninsight.com
 
3
 *
 
4
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Permission is hereby granted, free of charge, to any person obtaining a
 
8
 * copy of this software and associated documentation files (the "Software"),
 
9
 * to deal in the Software without restriction, including without limitation
 
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
11
 * and/or sell copies of the Software, and to permit persons to whom the
 
12
 * Software is furnished to do so, subject to the following conditions:
 
13
 * 
 
14
 * The above copyright notice and this permission notice (including the next
 
15
 * paragraph) shall be included in all copies or substantial portions of the
 
16
 * Software.
 
17
 * 
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
21
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
22
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
23
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
24
 * DEALINGS IN THE SOFTWARE.
 
25
 * 
 
26
 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
 
27
 *
 
28
 * DESCRIPTION
 
29
 *
 
30
 * This file contains a simple, straightforward implementation of the Park
 
31
 * & Miller "Minimal Standard" PRNG [PM88, PMS93], which is a Lehmer
 
32
 * multiplicative linear congruential generator (MLCG) with a period of
 
33
 * 2^31-1.
 
34
 *
 
35
 * This implementation is intended to provide a reliable, portable PRNG
 
36
 * that is suitable for testing a hash table implementation and for
 
37
 * implementing skip lists.
 
38
 *
 
39
 * FUTURE ENHANCEMENTS
 
40
 *
 
41
 * If initial seeds are not selected randomly, two instances of the PRNG
 
42
 * can be correlated.  [Knuth81, pp. 32-33] describes a shuffling technique
 
43
 * that can eliminate this problem.
 
44
 *
 
45
 * If PRNGs are used for simulation, the period of the current
 
46
 * implementation may be too short.  [LE88] discusses methods of combining
 
47
 * MLCGs to produce much longer periods, and suggests some alternative
 
48
 * values for A and M.  [LE90 and Sch92] also provide information on
 
49
 * long-period PRNGs.
 
50
 *
 
51
 * REFERENCES
 
52
 *
 
53
 * [Knuth81] Donald E. Knuth. The Art of Computer Programming.  Volume 2:
 
54
 * Seminumerical Algorithms.  Reading, Massachusetts: Addison-Wesley, 1981.
 
55
 *
 
56
 * [LE88] Pierre L'Ecuyer. "Efficient and Portable Combined Random Number
 
57
 * Generators".  CACM 31(6), June 1988, pp. 742-774.
 
58
 *
 
59
 * [LE90] Pierre L'Ecuyer. "Random Numbers for Simulation". CACM 33(10,
 
60
 * October 1990, pp. 85-97.
 
61
 *
 
62
 * [PM88] Stephen K. Park and Keith W. Miller. "Random Number Generators:
 
63
 * Good Ones are Hard to Find". CACM 31(10), October 1988, pp. 1192-1201.
 
64
 *
 
65
 * [Sch92] Bruce Schneier. "Pseudo-Ransom Sequence Generator for 32-Bit
 
66
 * CPUs".  Dr. Dobb's Journal 17(2), February 1992, pp. 34, 37-38, 40.
 
67
 *
 
68
 * [PMS93] Stephen K. Park, Keith W. Miller, and Paul K. Stockmeyer.  In
 
69
 * "Technical Correspondence: Remarks on Choosing and Implementing Random
 
70
 * Number Generators". CACM 36(7), July 1993, pp. 105-110.
 
71
 *
 
72
 */
 
73
 
 
74
#include <stdio.h>
 
75
#include <stdlib.h>
 
76
 
 
77
#define RANDOM_MAIN 0
 
78
 
 
79
#if !RANDOM_MAIN
 
80
# include "xf86drm.h"
 
81
#endif
 
82
 
 
83
#define RANDOM_MAGIC 0xfeedbeef
 
84
#define RANDOM_DEBUG 0
 
85
 
 
86
#if RANDOM_MAIN
 
87
#define RANDOM_ALLOC malloc
 
88
#define RANDOM_FREE  free
 
89
#else
 
90
#define RANDOM_ALLOC drmMalloc
 
91
#define RANDOM_FREE  drmFree
 
92
#endif
 
93
 
 
94
typedef struct RandomState {
 
95
    unsigned long magic;
 
96
    unsigned long a;
 
97
    unsigned long m;
 
98
    unsigned long q;            /* m div a */
 
99
    unsigned long r;            /* m mod a */
 
100
    unsigned long check;
 
101
    long          seed;
 
102
} RandomState;
 
103
 
 
104
#if RANDOM_MAIN
 
105
extern void          *drmRandomCreate(unsigned long seed);
 
106
extern int           drmRandomDestroy(void *state);
 
107
extern unsigned long drmRandom(void *state);
 
108
extern double        drmRandomDouble(void *state);
 
109
#endif
 
110
 
 
111
void *drmRandomCreate(unsigned long seed)
 
112
{
 
113
    RandomState  *state;
 
114
 
 
115
    state           = RANDOM_ALLOC(sizeof(*state));
 
116
    if (!state) return NULL;
 
117
    state->magic    = RANDOM_MAGIC;
 
118
#if 0
 
119
                                /* Park & Miller, October 1988 */
 
120
    state->a        = 16807;
 
121
    state->m        = 2147483647;
 
122
    state->check    = 1043618065; /* After 10000 iterations */
 
123
#else
 
124
                                /* Park, Miller, and Stockmeyer, July 1993 */
 
125
    state->a        = 48271;
 
126
    state->m        = 2147483647;
 
127
    state->check    = 399268537; /* After 10000 iterations */
 
128
#endif
 
129
    state->q        = state->m / state->a;
 
130
    state->r        = state->m % state->a;
 
131
 
 
132
    state->seed     = seed;
 
133
                                /* Check for illegal boundary conditions,
 
134
                                   and choose closest legal value. */
 
135
    if (state->seed <= 0)        state->seed = 1;
 
136
    if (state->seed >= state->m) state->seed = state->m - 1;
 
137
 
 
138
    return state;
 
139
}
 
140
 
 
141
int drmRandomDestroy(void *state)
 
142
{
 
143
    RANDOM_FREE(state);
 
144
    return 0;
 
145
}
 
146
 
 
147
unsigned long drmRandom(void *state)
 
148
{
 
149
    RandomState   *s = (RandomState *)state;
 
150
    long          hi;
 
151
    long          lo;
 
152
 
 
153
    hi      = s->seed / s->q;
 
154
    lo      = s->seed % s->q;
 
155
    s->seed = s->a * lo - s->r * hi;
 
156
    if (s->seed <= 0) s->seed += s->m;
 
157
 
 
158
    return s->seed;
 
159
}
 
160
 
 
161
double drmRandomDouble(void *state)
 
162
{
 
163
    RandomState *s = (RandomState *)state;
 
164
    
 
165
    return (double)drmRandom(state)/(double)s->m;
 
166
}
 
167
 
 
168
#if RANDOM_MAIN
 
169
static void check_period(long seed)
 
170
{
 
171
    unsigned long count = 0;
 
172
    unsigned long initial;
 
173
    void          *state;
 
174
    
 
175
    state = drmRandomCreate(seed);
 
176
    initial = drmRandom(state);
 
177
    ++count;
 
178
    while (initial != drmRandom(state)) {
 
179
        if (!++count) break;
 
180
    }
 
181
    printf("With seed of %10ld, period = %10lu (0x%08lx)\n",
 
182
           seed, count, count);
 
183
    drmRandomDestroy(state);
 
184
}
 
185
 
 
186
int main(void)
 
187
{
 
188
    RandomState   *state;
 
189
    int           i;
 
190
    unsigned long rand;
 
191
 
 
192
    state = drmRandomCreate(1);
 
193
    for (i = 0; i < 10000; i++) {
 
194
        rand = drmRandom(state);
 
195
    }
 
196
    printf("After 10000 iterations: %lu (%lu expected): %s\n",
 
197
           rand, state->check,
 
198
           rand - state->check ? "*INCORRECT*" : "CORRECT");
 
199
    drmRandomDestroy(state);
 
200
 
 
201
    printf("Checking periods...\n");
 
202
    check_period(1);
 
203
    check_period(2);
 
204
    check_period(31415926);
 
205
    
 
206
    return 0;
 
207
}
 
208
#endif