source: cpp/common/random.h @ 1139

Last change on this file since 1139 was 1005, checked in by Maciej Komosinski, 4 years ago

Higher conformance with C++17, but gave up after missing M_PI, M_PI_2, strdup() and more; other cosmetic improvements

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