source: cpp/common/random.h @ 741

Last change on this file since 741 was 324, checked in by Maciej Komosinski, 10 years ago

#include <stdint.h> for all platforms

  • Property svn:eol-style set to native
File size: 3.0 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "nonstd.h" //LONGLONG
6#include <time.h> //time()
7#include <stdint.h> //uintptr_t
8#ifdef MULTITHREADED
9 #include "threads.h"
10#endif
11#ifdef LINUX
12 #include <unistd.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15#endif
16#ifdef _WIN32
17 #define _WINSOCKAPI_ //http://stackoverflow.com/questions/1372480/c-redefinition-header-files
18 #include <rpc.h> //UUID
19 #pragma comment(lib, "Rpcrt4.lib")
20#endif
21
22//adapted from
23//http://en.wikipedia.org/wiki/Mersenne_twister#Pseudocode
24//http://my.opera.com/metrallik/blog/2013/04/19/c-class-for-random-generation-with-mersenne-twister-method
25
26class RandomGenerator
27{
28private:
29        static const unsigned int length = 624;
30        static const unsigned int bitMask_32 = 0xffffffff;
31        static const unsigned int bitPow_31 = 1 << 31;
32        static const unsigned int MAXVALUE = 0xffffffff;
33        unsigned int counter; //only used in randomize(). uninitialized is OK
34#ifdef MULTITHREADED
35        pthread_mutex_t lock;
36#endif
37        unsigned int *mt;
38        unsigned int idx;
39public:
40
41        RandomGenerator(unsigned int seed)
42        {
43#ifdef MULTITHREADED
44                pthread_mutex_init(&lock, NULL);
45#endif
46                mt = new unsigned int[length];
47                setSeed(seed);
48        }
49
50        inline void setSeed(unsigned int seed)
51        {
52#ifdef MULTITHREADED
53                pthread_mutex_lock(&lock);
54#endif
55                idx = 0;
56                mt[0] = seed;
57                for (unsigned int i = 1; i < length; i++)
58                        mt[i] = (1812433253 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i)&bitMask_32;
59#ifdef MULTITHREADED
60                pthread_mutex_unlock(&lock);
61#endif
62        }
63
64        unsigned int randomize()
65        {
66                unsigned int seed;
67                //for ms visual, could use http://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx
68#ifdef LINUX
69                int fd=open("/dev/urandom",O_RDONLY);
70                if (fd>=0)
71                {
72                        read(fd,&seed,sizeof(seed));
73                        close(fd);
74                }
75                else
76#endif
77                {
78                        counter++;
79                        seed = time(NULL);                         //time (seconds); could use hi-res timer but then we would depend on common/timer.h
80                        seed ^= counter;                           //incremented value, possibly randomly initialized
81                        seed ^= (unsigned int)(uintptr_t)&counter; //memory address
82                }
83#ifdef _WIN32 //add more randomness from uuid
84                UUID uuid;
85                ::UuidCreate(&uuid);
86                seed ^= uuid.Data1^uuid.Data2^uuid.Data3^uuid.Data4[0];
87#endif
88                setSeed(seed);
89                return seed;
90        }
91
92        inline unsigned int getUint32()
93        {
94#ifdef MULTITHREADED
95                pthread_mutex_lock(&lock);
96#endif
97                if (idx == 0) gen();
98                unsigned int y = mt[idx];
99                idx = (idx + 1) % length;
100#ifdef MULTITHREADED
101                pthread_mutex_unlock(&lock);
102#endif
103                y ^= y >> 11;
104                y ^= (y << 7) & 2636928640U;
105                y ^= (y << 15) & 4022730752U;
106                y ^= y >> 18;
107                return y;
108        }
109
110        inline double getDouble() // [0,1)
111        {
112                return double(getUint32()) / ((LONGLONG)(MAXVALUE)+1);
113        }
114
115        inline void gen()
116        {
117                for (unsigned int i = 0; i < length; i++)
118                {
119                        unsigned int y = (mt[i] & bitPow_31) + (mt[(i + 1) % length] & (bitPow_31 - 1));
120                        mt[i] = mt[(i + 397) % length] ^ (y >> 1);
121                        if (y % 2) mt[i] ^= 2567483615U;
122                }
123                return;
124        }
125
126        ~RandomGenerator()
127        {
128                delete[] mt;
129        }
130};
Note: See TracBrowser for help on using the repository browser.