File: random.cc

package info (click to toggle)
xmahjongg 3.5-2
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,060 kB
  • ctags: 1,317
  • sloc: cpp: 5,619; ansic: 3,451; sh: 330; makefile: 162
file content (100 lines) | stat: -rw-r--r-- 2,310 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "game.hh"
#include <stdio.h>
#include <stdlib.h>

#define M 1000000000
#define M_inv 1.0E-9
#define L 24
#define K 55
#define D 21

/*
  Random number generator.
    Uses the subtractive series
    
	X[n] = (X[n-55] - X[n-24]) mod M, n >= 55
	
    as suggested in Seminumerical Algorithms, exercise 3.2.2--23.
    Knuth gives a FORTRAN implementation in section 3.6 for use as a
    portable random number generator.

		Michael Coffin
*/

/*
    The constant M is machine dependent.  It must be even, and
    integer arithmetic on the range [-M,+M] must be possible.  The
    function random() returns values in the half-open interval [0,M).
    
    Minv is just 1/M.

    Other possible values for L and K can be chosen from Table 1 of
    Section 3.2.2. The constant D should be relatively prime to K and
    approximately 0.382*K.  (Don't ask me why.)

    To get a random number in the real interval [X,Y) the recommended
    formula is (X + (frandom() * (Y-X))).  For an integral interval,
    take the floor.
*/

/* current state of generator */
static u_int32_t X[K];		/* Fibonacci array */
static int cur;			/* Current index in array.   */
static int curL;		/* this is always (cur - L) mod K */


/* seed the generator */
void
zrand_seed(u_int32_t seed)
{
  int i;
  u_int32_t j, k;
  
  /* Make zrandom() repeatable: Always reset X, cur and curL to their initial
     values. -ed */
  cur = 0;
  curL = K - L;
  for (i = 0; i < K; i++)
    X[i] = 0;
  
  /* According to Knuth, "This computes a Fibonacci-like sequence; */
  /* multiplication of indices by 21 [the constant D] spreads the */
  /* values around so as to alleviate initial nonrandomness */
  /* problems..." */ 
  seed = seed % M;
  
  X[0] = j = seed;
  k = 1;
  
  for (i = 1; i < K; i++) {
    int which = (D*i) % K;
    X[which] = k;
    if (j < k) k -= M;
    k = j - k;
    j = X[which];
  }
  
  /* `warm up' the generator. Three was good enough for Knuth... */
  for (i = 0; i < 5 * K; i++)
    zrand();
}


/* return next value in the sequence */
u_int32_t
zrand()
{
  u_int32_t result;
  
  result = X[cur] < X[curL] ? M : 0;
  result += X[cur] - X[curL];
  X[cur] = result;
  
  cur++; if (cur == K) cur = 0;
  curL++; if (curL == K) curL = 0;
  
  return result;
}