chiark / gitweb /
Rearrange the file tree.
[catacomb] / rand / grand.c
1 /* -*-c-*-
2  *
3  * Generic interface to random number generators
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <stddef.h>
31
32 #include <mLib/bits.h>
33
34 #include "grand.h"
35
36 /*----- Main code ---------------------------------------------------------*/
37
38 /* --- @grand_byte@ --- *
39  *
40  * Arguments:   @grand *r@ = pointet to generic generator
41  *
42  * Returns:     A uniformly-distributed pseudorandom integer in the interval
43  *              %$[0, 256)$%.
44  */
45
46 octet grand_byte(grand *r)
47 {
48   if (r->ops->byte != grand_byte)
49     return (r->ops->byte(r));
50   else if (r->ops->word != grand_word)
51     return (r->ops->word(r) & 0xff);
52   else if (r->ops->fill != grand_fill) {
53     octet o;
54     r->ops->fill(r, &o, 1);
55     return (o);
56   } else
57     return (grand_range(r, 256));
58 }
59
60 /* --- @grand_word@ --- *
61  *
62  * Arguments:   @grand *r@ = pointet to generic generator
63  *
64  * Returns:     A uniformly-distributed pseudorandom integer in the interval
65  *              %$[0, 2^{32})$%.
66  */
67
68 uint32 grand_word(grand *r)
69 {
70   if (r->ops->word != grand_word)
71     return (r->ops->word(r));
72   else {
73     octet b[4];
74     grand_fill(r, b, sizeof(b));
75     return (LOAD32(b));
76   }
77 }
78
79 /* --- @grand_range@ --- *
80  *
81  * Arguments:   @grand *r@ = pointet to generic generator
82  *              @uint32 l@ = limit for acceptable results
83  *
84  * Returns:     A uniformly-distributed pseudorandom integer in the interval
85  *              %$[0, l)$%.
86  */
87
88 uint32 grand_range(grand *r, uint32 l)
89 {
90   if (r->ops->range != grand_range)
91     return (r->ops->range(r, l));
92   else {
93     uint32 m, z;
94     uint32 (*w)(grand */*r*/);
95     uint32 x;
96
97     /* --- Decide where to get data from --- *
98      *
99      * The choice of %$2^{32} - 1$% as a limit when using @grand_word@ isn't
100      * wonderful, but working with %$2^{32}$% is awkward and the loss of a
101      * few return values isn't significant.  The algorithm below still
102      * successfully returns uniformly distributed results.
103      */
104
105     if (r->ops->max) {
106       w = r->ops->raw;
107       m = r->ops->max;
108     } else {
109       w = grand_word;
110       m = 0xffffffff;
111     }
112
113     /* --- Work out maximum acceptable return value --- *
114      *
115      * This will be the highest multiple of @l@ less than @m@.
116      */
117
118     z = m - (m % l);
119
120     /* --- Generate numbers until something acceptable is found --- *
121      *
122      * This will require an expected number of attempts less than 2.
123      */
124
125     do x = w(r); while (x >= z);
126     return (x % l);
127   }
128 }
129
130 /* --- @grand_fill@ --- *
131  *
132  * Arguments:   @grand *r@ = pointet to generic generator
133  *              @void *p@ = pointer to a buffer
134  *              @size_t sz@ = size of the buffer
135  *
136  * Returns:     ---
137  *
138  * Use:         Fills a buffer with uniformly distributed pseudorandom bytes
139  *              (see @grand_byte@).
140  */
141
142 void grand_fill(grand *r, void *p, size_t sz)
143 {
144   if (r->ops->fill != grand_fill)
145     r->ops->fill(r, p, sz);
146   else {
147     octet *q = p;
148     while (sz) {
149       *q++ = r->ops->byte(r);
150       sz--;
151     }
152   }
153 }
154
155 /*----- That's all, folks -------------------------------------------------*/