source: cpp/common/random.h @ 886

Last change on this file since 886 was 886, checked in by Maciej Komosinski, 5 years ago

LONGLONG no longer needed as long as int64_t became standard

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