xref: /openbsd-src/regress/lib/libc/cephes/drand.c (revision b7275c8844bfe6dc0cf95984cd963da8316ddba7)
1*b7275c88Smartynas /*	$OpenBSD: drand.c,v 1.1 2011/07/02 18:11:01 martynas Exp $	*/
2*b7275c88Smartynas 
3*b7275c88Smartynas /*
4*b7275c88Smartynas  * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
5*b7275c88Smartynas  *
6*b7275c88Smartynas  * Permission to use, copy, modify, and distribute this software for any
7*b7275c88Smartynas  * purpose with or without fee is hereby granted, provided that the above
8*b7275c88Smartynas  * copyright notice and this permission notice appear in all copies.
9*b7275c88Smartynas  *
10*b7275c88Smartynas  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*b7275c88Smartynas  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*b7275c88Smartynas  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*b7275c88Smartynas  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*b7275c88Smartynas  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*b7275c88Smartynas  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*b7275c88Smartynas  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*b7275c88Smartynas  */
18*b7275c88Smartynas 
19*b7275c88Smartynas /*							drand.c
20*b7275c88Smartynas  *
21*b7275c88Smartynas  *	Pseudorandom number generator
22*b7275c88Smartynas  *
23*b7275c88Smartynas  *
24*b7275c88Smartynas  *
25*b7275c88Smartynas  * SYNOPSIS:
26*b7275c88Smartynas  *
27*b7275c88Smartynas  * double y, drand();
28*b7275c88Smartynas  *
29*b7275c88Smartynas  * drand( &y );
30*b7275c88Smartynas  *
31*b7275c88Smartynas  *
32*b7275c88Smartynas  *
33*b7275c88Smartynas  * DESCRIPTION:
34*b7275c88Smartynas  *
35*b7275c88Smartynas  * Yields a random number 1.0 <= y < 2.0.
36*b7275c88Smartynas  *
37*b7275c88Smartynas  * The three-generator congruential algorithm by Brian
38*b7275c88Smartynas  * Wichmann and David Hill (BYTE magazine, March, 1987,
39*b7275c88Smartynas  * pp 127-8) is used. The period, given by them, is
40*b7275c88Smartynas  * 6953607871644.
41*b7275c88Smartynas  *
42*b7275c88Smartynas  * Versions invoked by the different arithmetic compile
43*b7275c88Smartynas  * time options DEC, IBMPC, and MIEEE, produce
44*b7275c88Smartynas  * approximately the same sequences, differing only in the
45*b7275c88Smartynas  * least significant bits of the numbers. The UNK option
46*b7275c88Smartynas  * implements the algorithm as recommended in the BYTE
47*b7275c88Smartynas  * article.  It may be used on all computers. However,
48*b7275c88Smartynas  * the low order bits of a double precision number may
49*b7275c88Smartynas  * not be adequately random, and may vary due to arithmetic
50*b7275c88Smartynas  * implementation details on different computers.
51*b7275c88Smartynas  *
52*b7275c88Smartynas  * The other compile options generate an additional random
53*b7275c88Smartynas  * integer that overwrites the low order bits of the double
54*b7275c88Smartynas  * precision number.  This reduces the period by a factor of
55*b7275c88Smartynas  * two but tends to overcome the problems mentioned.
56*b7275c88Smartynas  *
57*b7275c88Smartynas  */
58*b7275c88Smartynas 
59*b7275c88Smartynas #include "mconf.h"
60*b7275c88Smartynas 
61*b7275c88Smartynas 
62*b7275c88Smartynas /*  Three-generator random number algorithm
63*b7275c88Smartynas  * of Brian Wichmann and David Hill
64*b7275c88Smartynas  * BYTE magazine, March, 1987 pp 127-8
65*b7275c88Smartynas  *
66*b7275c88Smartynas  * The period, given by them, is (p-1)(q-1)(r-1)/4 = 6.95e12.
67*b7275c88Smartynas  */
68*b7275c88Smartynas 
69*b7275c88Smartynas static int sx = 1;
70*b7275c88Smartynas static int sy = 10000;
71*b7275c88Smartynas static int sz = 3000;
72*b7275c88Smartynas 
73*b7275c88Smartynas static union {
74*b7275c88Smartynas  double d;
75*b7275c88Smartynas  unsigned short s[4];
76*b7275c88Smartynas } unkans;
77*b7275c88Smartynas 
78*b7275c88Smartynas /* This function implements the three
79*b7275c88Smartynas  * congruential generators.
80*b7275c88Smartynas  */
81*b7275c88Smartynas 
ranwh()82*b7275c88Smartynas static int ranwh()
83*b7275c88Smartynas {
84*b7275c88Smartynas int r, s;
85*b7275c88Smartynas 
86*b7275c88Smartynas /*  sx = sx * 171 mod 30269 */
87*b7275c88Smartynas r = sx/177;
88*b7275c88Smartynas s = sx - 177 * r;
89*b7275c88Smartynas sx = 171 * s - 2 * r;
90*b7275c88Smartynas if( sx < 0 )
91*b7275c88Smartynas 	sx += 30269;
92*b7275c88Smartynas 
93*b7275c88Smartynas 
94*b7275c88Smartynas /* sy = sy * 172 mod 30307 */
95*b7275c88Smartynas r = sy/176;
96*b7275c88Smartynas s = sy - 176 * r;
97*b7275c88Smartynas sy = 172 * s - 35 * r;
98*b7275c88Smartynas if( sy < 0 )
99*b7275c88Smartynas 	sy += 30307;
100*b7275c88Smartynas 
101*b7275c88Smartynas /* sz = 170 * sz mod 30323 */
102*b7275c88Smartynas r = sz/178;
103*b7275c88Smartynas s = sz - 178 * r;
104*b7275c88Smartynas sz = 170 * s - 63 * r;
105*b7275c88Smartynas if( sz < 0 )
106*b7275c88Smartynas 	sz += 30323;
107*b7275c88Smartynas /* The results are in static sx, sy, sz. */
108*b7275c88Smartynas return 0;
109*b7275c88Smartynas }
110*b7275c88Smartynas 
111*b7275c88Smartynas /*	drand.c
112*b7275c88Smartynas  *
113*b7275c88Smartynas  * Random double precision floating point number between 1 and 2.
114*b7275c88Smartynas  *
115*b7275c88Smartynas  * C callable:
116*b7275c88Smartynas  *	drand( &x );
117*b7275c88Smartynas  */
118*b7275c88Smartynas 
drand(a)119*b7275c88Smartynas int drand( a )
120*b7275c88Smartynas double *a;
121*b7275c88Smartynas {
122*b7275c88Smartynas unsigned short r;
123*b7275c88Smartynas #ifdef DEC
124*b7275c88Smartynas unsigned short s, t;
125*b7275c88Smartynas #endif
126*b7275c88Smartynas 
127*b7275c88Smartynas /* This algorithm of Wichmann and Hill computes a floating point
128*b7275c88Smartynas  * result:
129*b7275c88Smartynas  */
130*b7275c88Smartynas ranwh();
131*b7275c88Smartynas unkans.d = sx/30269.0  +  sy/30307.0  +  sz/30323.0;
132*b7275c88Smartynas r = unkans.d;
133*b7275c88Smartynas unkans.d -= r;
134*b7275c88Smartynas unkans.d += 1.0;
135*b7275c88Smartynas 
136*b7275c88Smartynas /* if UNK option, do nothing further.
137*b7275c88Smartynas  * Otherwise, make a random 16 bit integer
138*b7275c88Smartynas  * to overwrite the least significant word
139*b7275c88Smartynas  * of unkans.
140*b7275c88Smartynas  */
141*b7275c88Smartynas #ifdef UNK
142*b7275c88Smartynas /* do nothing */
143*b7275c88Smartynas #else
144*b7275c88Smartynas ranwh();
145*b7275c88Smartynas r = sx * sy + sz;
146*b7275c88Smartynas #endif
147*b7275c88Smartynas 
148*b7275c88Smartynas #ifdef DEC
149*b7275c88Smartynas /* To make the numbers as similar as possible
150*b7275c88Smartynas  * in all arithmetics, the random integer has
151*b7275c88Smartynas  * to be inserted 3 bits higher up in a DEC number.
152*b7275c88Smartynas  * An alternative would be put it 3 bits lower down
153*b7275c88Smartynas  * in all the other number types.
154*b7275c88Smartynas  */
155*b7275c88Smartynas s = unkans.s[2];
156*b7275c88Smartynas t = s & 07;	/* save these bits to put in at the bottom */
157*b7275c88Smartynas s &= 0177770;
158*b7275c88Smartynas s |= (r >> 13) & 07;
159*b7275c88Smartynas unkans.s[2] = s;
160*b7275c88Smartynas t |= r << 3;
161*b7275c88Smartynas unkans.s[3] = t;
162*b7275c88Smartynas #endif
163*b7275c88Smartynas 
164*b7275c88Smartynas #ifdef IBMPC
165*b7275c88Smartynas unkans.s[0] = r;
166*b7275c88Smartynas #endif
167*b7275c88Smartynas 
168*b7275c88Smartynas #ifdef MIEEE
169*b7275c88Smartynas unkans.s[3] = r;
170*b7275c88Smartynas #endif
171*b7275c88Smartynas 
172*b7275c88Smartynas *a = unkans.d;
173*b7275c88Smartynas return 0;
174*b7275c88Smartynas }
175