source: cpp/common/random.h @ 852

Last change on this file since 852 was 843, checked in by Maciej Komosinski, 6 years ago

Our random number generator class becomes compatible with std::UniformRandomBitGenerator?

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