Statistics
| Revision:

svn-gvsig-desktop / tags / v1_0_2_Build_907 / extensions / extScripting / scripts / jython / Lib / whrandom.py @ 11015

History | View | Annotate | Download (4.67 KB)

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