Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
whrandom.py
Go to the documentation of this file.
1 """Wichman-Hill random number generator.
2 
3 Wichmann, B. A. & Hill, I. D. (1982)
4 Algorithm AS 183:
5 An efficient and portable pseudo-random number generator
6 Applied Statistics 31 (1982) 188-190
7 
8 see also:
9  Correction to Algorithm AS 183
10  Applied Statistics 33 (1984) 123
11 
12  McLeod, A. I. (1985)
13  A remark on Algorithm AS 183
14  Applied Statistics 34 (1985),198-200
15 
16 
17 USE:
18 whrandom.random() yields double precision random numbers
19  uniformly distributed between 0 and 1.
20 
21 whrandom.seed(x, y, z) must be called before whrandom.random()
22  to seed the generator
23 
24 There is also an interface to create multiple independent
25 random generators, and to choose from other ranges.
26 
27 
28 
29 Multi-threading note: the random number generator used here is not
30 thread-safe; it is possible that nearly simultaneous calls in
31 different theads return the same random value. To avoid this, you
32 have to use a lock around all calls. (I didn't want to slow this
33 down in the serial case by using a lock here.)
34 """
35 
36 # Translated by Guido van Rossum from C source provided by
37 # Adrian Baddeley.
38 
39 
40 class whrandom:
41  def __init__(self, x = 0, y = 0, z = 0):
42  """Initialize an instance.
43  Without arguments, initialize from current time.
44  With arguments (x, y, z), initialize from them."""
45  self.seed(x, y, z)
46 
47  def seed(self, x = 0, y = 0, z = 0):
48  """Set the seed from (x, y, z).
49  These must be integers in the range [0, 256)."""
50  if not type(x) == type(y) == type(z) == type(0):
51  raise TypeError, 'seeds must be integers'
52  if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
53  raise ValueError, 'seeds must be in range(0, 256)'
54  if 0 == x == y == z:
55  # Initialize from current time
56  import time
57  t = long(time.time() * 256)
58  t = int((t&0xffffff) ^ (t>>24))
59  t, x = divmod(t, 256)
60  t, y = divmod(t, 256)
61  t, z = divmod(t, 256)
62  # Zero is a poor seed, so substitute 1
63  self._seed = (x or 1, y or 1, z or 1)
64 
65  def random(self):
66  """Get the next random number in the range [0.0, 1.0)."""
67  # This part is thread-unsafe:
68  # BEGIN CRITICAL SECTION
69  x, y, z = self._seed
70  #
71  x = (171 * x) % 30269
72  y = (172 * y) % 30307
73  z = (170 * z) % 30323
74  #
75  self._seed = x, y, z
76  # END CRITICAL SECTION
77  #
78  return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
79 
80  def uniform(self, a, b):
81  """Get a random number in the range [a, b)."""
82  return a + (b-a) * self.random()
83 
84  def randint(self, a, b):
85  """Get a random integer in the range [a, b] including
86  both end points.
87 
88  (Deprecated; use randrange below.)"""
89  return self.randrange(a, b+1)
90 
91  def choice(self, seq):
92  """Choose a random element from a non-empty sequence."""
93  return seq[int(self.random() * len(seq))]
94 
95  def randrange(self, start, stop=None, step=1, int=int, default=None):
96  """Choose a random item from range(start, stop[, step]).
97 
98  This fixes the problem with randint() which includes the
99  endpoint; in Python this is usually not what you want.
100  Do not supply the 'int' and 'default' arguments."""
101  # This code is a bit messy to make it fast for the
102  # common case while still doing adequate error checking
103  istart = int(start)
104  if istart != start:
105  raise ValueError, "non-integer arg 1 for randrange()"
106  if stop is default:
107  if istart > 0:
108  return int(self.random() * istart)
109  raise ValueError, "empty range for randrange()"
110  istop = int(stop)
111  if istop != stop:
112  raise ValueError, "non-integer stop for randrange()"
113  if step == 1:
114  if istart < istop:
115  return istart + int(self.random() *
116  (istop - istart))
117  raise ValueError, "empty range for randrange()"
118  istep = int(step)
119  if istep != step:
120  raise ValueError, "non-integer step for randrange()"
121  if istep > 0:
122  n = (istop - istart + istep - 1) / istep
123  elif istep < 0:
124  n = (istop - istart + istep + 1) / istep
125  else:
126  raise ValueError, "zero step for randrange()"
127 
128  if n <= 0:
129  raise ValueError, "empty range for randrange()"
130  return istart + istep*int(self.random() * n)
131 
132 
133 # Initialize from the current time
134 _inst = whrandom()
135 seed = _inst.seed
136 random = _inst.random
137 uniform = _inst.uniform
138 randint = _inst.randint
139 choice = _inst.choice
140 randrange = _inst.randrange