4 * Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org)
6 * The rk_random and rk_seed functions algorithms and the original design of
7 * the Mersenne Twister RNG:
9 * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * 3. The names of its contributors may not be used to endorse or promote
24 * products derived from this software without specific prior written
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * Original algorithm for the implementation of rk_interval function from
40 * Richard J. Wagner's implementation of the Mersenne Twister RNG, optimised by
43 * Constants used in the rk_double implementation by Isaku Wada.
45 * Permission is hereby granted, free of charge, to any person obtaining a
46 * copy of this software and associated documentation files (the
47 * "Software"), to deal in the Software without restriction, including
48 * without limitation the rights to use, copy, modify, merge, publish,
49 * distribute, sublicense, and/or sell copies of the Software, and to
50 * permit persons to whom the Software is furnished to do so, subject to
51 * the following conditions:
53 * The above copyright notice and this permission notice shall be included
54 * in all copies or substantial portions of the Software.
56 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
57 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
58 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
59 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
60 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
61 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
62 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
65 /* static char const rcsid[] =
66 "@(#) $Jeannot: randomkit.c,v 1.28 2005/07/21 22:14:09 js Exp $"; */
77 * XXX: we have to use this ugly defined(__GNUC__) because it is not easy to
78 * detect the compiler used in distutils itself
80 #if (defined(__GNUC__) && defined(NPY_NEEDS_MINGW_TIME_WORKAROUND))
83 * FIXME: ideally, we should set this to the real version of MSVCRT. We need
84 * something higher than 0x601 to enable _ftime64 and co
86 #define __MSVCRT_VERSION__ 0x0700
88 #include <sys/timeb.h>
91 * mingw msvcr lib import wrongly export _ftime, which does not exist in the
92 * actual msvc runtime for version >= 8; we make it an alias to _ftime64, which
93 * is available in those versions of the runtime
95 #define _FTIME(x) _ftime64((x))
98 #include <sys/timeb.h>
99 #define _FTIME(x) _ftime((x))
102 #ifndef RK_NO_WINCRYPT
105 #define _WIN32_WINNT 0x0400
108 #include <wincrypt.h>
114 #include <sys/time.h>
118 #include "randomkit.h"
120 #ifndef RK_DEV_URANDOM
121 #define RK_DEV_URANDOM "/dev/urandom"
124 #ifndef RK_DEV_RANDOM
125 #define RK_DEV_RANDOM "/dev/random"
128 char *rk_strerror
[RK_ERR_MAX
] =
131 "random device unvavailable"
134 /* static functions */
135 static unsigned long rk_hash(unsigned long key
);
138 rk_seed(unsigned long seed
, rk_state
*state
)
141 seed
&= 0xffffffffUL
;
143 /* Knuth's PRNG as used in the Mersenne Twister reference implementation */
144 for (pos
= 0; pos
< RK_STATE_LEN
; pos
++) {
145 state
->key
[pos
] = seed
;
146 seed
= (1812433253UL * (seed
^ (seed
>> 30)) + pos
+ 1) & 0xffffffffUL
;
148 state
->pos
= RK_STATE_LEN
;
150 state
->has_gauss
= 0;
151 state
->has_binomial
= 0;
154 /* Thomas Wang 32 bits integer hash function */
156 rk_hash(unsigned long key
)
168 rk_randomseed(rk_state
*state
)
177 if (rk_devfill(state
->key
, sizeof(state
->key
), 0) == RK_NOERR
) {
178 /* ensures non-zero key */
179 state
->key
[0] |= 0x80000000UL
;
180 state
->pos
= RK_STATE_LEN
;
182 state
->has_gauss
= 0;
183 state
->has_binomial
= 0;
185 for (i
= 0; i
< 624; i
++) {
186 state
->key
[i
] &= 0xffffffffUL
;
192 gettimeofday(&tv
, NULL
);
193 rk_seed(rk_hash(getpid()) ^ rk_hash(tv
.tv_sec
) ^ rk_hash(tv
.tv_usec
)
194 ^ rk_hash(clock()), state
);
197 rk_seed(rk_hash(tv
.time
) ^ rk_hash(tv
.millitm
) ^ rk_hash(clock()), state
);
203 /* Magic Mersenne Twister constants */
206 #define MATRIX_A 0x9908b0dfUL
207 #define UPPER_MASK 0x80000000UL
208 #define LOWER_MASK 0x7fffffffUL
210 /* Slightly optimised reference implementation of the Mersenne Twister */
212 rk_random(rk_state
*state
)
216 if (state
->pos
== RK_STATE_LEN
) {
219 for (i
= 0; i
< N
- M
; i
++) {
220 y
= (state
->key
[i
] & UPPER_MASK
) | (state
->key
[i
+1] & LOWER_MASK
);
221 state
->key
[i
] = state
->key
[i
+M
] ^ (y
>>1) ^ (-(y
& 1) & MATRIX_A
);
223 for (; i
< N
- 1; i
++) {
224 y
= (state
->key
[i
] & UPPER_MASK
) | (state
->key
[i
+1] & LOWER_MASK
);
225 state
->key
[i
] = state
->key
[i
+(M
-N
)] ^ (y
>>1) ^ (-(y
& 1) & MATRIX_A
);
227 y
= (state
->key
[N
- 1] & UPPER_MASK
) | (state
->key
[0] & LOWER_MASK
);
228 state
->key
[N
- 1] = state
->key
[M
- 1] ^ (y
>> 1) ^ (-(y
& 1) & MATRIX_A
);
232 y
= state
->key
[state
->pos
++];
236 y
^= (y
<< 7) & 0x9d2c5680UL
;
237 y
^= (y
<< 15) & 0xefc60000UL
;
244 rk_long(rk_state
*state
)
246 return rk_ulong(state
) >> 1;
250 rk_ulong(rk_state
*state
)
252 #if ULONG_MAX <= 0xffffffffUL
253 return rk_random(state
);
255 return (rk_random(state
) << 32) | (rk_random(state
));
260 rk_interval(unsigned long max
, rk_state
*state
)
262 unsigned long mask
= max
, value
;
267 /* Smallest bit mask >= max */
273 #if ULONG_MAX > 0xffffffffUL
277 /* Search a random value in [0..mask] <= max */
278 #if ULONG_MAX > 0xffffffffUL
279 if (max
<= 0xffffffffUL
) {
280 while ((value
= (rk_random(state
) & mask
)) > max
);
283 while ((value
= (rk_ulong(state
) & mask
)) > max
);
286 while ((value
= (rk_ulong(state
) & mask
)) > max
);
292 rk_double(rk_state
*state
)
294 /* shifts : 67108864 = 0x4000000, 9007199254740992 = 0x20000000000000 */
295 long a
= rk_random(state
) >> 5, b
= rk_random(state
) >> 6;
296 return (a
* 67108864.0 + b
) / 9007199254740992.0;
300 rk_fill(void *buffer
, size_t size
, rk_state
*state
)
303 unsigned char *buf
= buffer
;
305 for (; size
>= 4; size
-= 4) {
306 r
= rk_random(state
);
308 *(buf
++) = (r
>> 8) & 0xFF;
309 *(buf
++) = (r
>> 16) & 0xFF;
310 *(buf
++) = (r
>> 24) & 0xFF;
316 r
= rk_random(state
);
317 for (; size
; r
>>= 8, size
--) {
318 *(buf
++) = (unsigned char)(r
& 0xFF);
323 rk_devfill(void *buffer
, size_t size
, int strong
)
330 rfile
= fopen(RK_DEV_RANDOM
, "rb");
333 rfile
= fopen(RK_DEV_URANDOM
, "rb");
338 done
= fread(buffer
, size
, 1, rfile
);
345 #ifndef RK_NO_WINCRYPT
346 HCRYPTPROV hCryptProv
;
349 if (!CryptAcquireContext(&hCryptProv
, NULL
, NULL
, PROV_RSA_FULL
,
350 CRYPT_VERIFYCONTEXT
) || !hCryptProv
) {
353 done
= CryptGenRandom(hCryptProv
, size
, (unsigned char *)buffer
);
354 CryptReleaseContext(hCryptProv
, 0);
365 rk_altfill(void *buffer
, size_t size
, int strong
, rk_state
*state
)
369 err
= rk_devfill(buffer
, size
, strong
);
371 rk_fill(buffer
, size
, state
);
377 rk_gauss(rk_state
*state
)
379 if (state
->has_gauss
) {
380 const double tmp
= state
->gauss
;
382 state
->has_gauss
= 0;
386 double f
, x1
, x2
, r2
;
389 x1
= 2.0*rk_double(state
) - 1.0;
390 x2
= 2.0*rk_double(state
) - 1.0;
393 while (r2
>= 1.0 || r2
== 0.0);
395 /* Box-Muller transform */
396 f
= sqrt(-2.0*log(r2
)/r2
);
397 /* Keep for next call */
399 state
->has_gauss
= 1;