source: cpp/common/random.h @ 260

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

Sources support both 32-bit and 64-bit, and more compilers

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