source: cpp/common/random.h @ 238

Last change on this file since 238 was 197, checked in by Maciej Komosinski, 11 years ago

GDK used by developers since 1999, distributed on the web since 2002

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