1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/rt/Random.hpp>
  7 #ifdef _WIN32
  8 #define _CRT_RAND_S
  9 #define WIN32_LEAN_AND_MEAN
 10 #include <Windows.h>
 11 #else
 12 #include <unistd.h>
 13 #include <sys/types.h>
 14 #include <sys/stat.h>
 15 #include <fcntl.h>
 16 #endif
 17 #include <stdlib.h>
 18 #include <string.h>
 19 #include <stdio.h>
 20 
 21 #ifdef _WIN32
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 #else
 36 
 37 uint32_t RtGetRandomSeed()
 38 {
 39     unsigned int seed = 0;
 40     int fn = open("/dev/urandom"O_RDONLY);
 41     if (fn == -1)
 42     {
 43         perror("RtGetRandomSeed() failed");
 44         exit(1);
 45     }
 46     if (read(fn&seed4) != 4)
 47     {
 48         perror("RtGetRandomSeed() failed");
 49         exit(1);
 50     }
 51     close(fn);
 52     return seed;
 53 }
 54 
 55 #endif
 56 
 57 namespace cmajor { namespace rt {
 58 
 59 class MT 
 60 {
 61 private:
 62     static const int32_t n = 624;
 63     static const int32_t m = 397;
 64     static const uint32_t matrixA = 0x9908b0dfu;
 65     static const uint32_t upperMask = 0x80000000u;
 66     static const uint32_t lowerMask = 0x7fffffffu;
 67 public:
 68     MT();
 69     bool Initialized()
 70     {
 71         return initialized;
 72     }
 73     void InitWithRandomSeed()
 74     {
 75         uint32_t seed = RtGetRandomSeed();
 76         Init(seed);
 77     }
 78     void Init(uint32_t seed)
 79     {
 80         initialized = true;
 81         mt[0] = seed;
 82         for (mti = 1; mti < n; ++mti)
 83         {
 84             mt[mti] = 1812433253u * (mt[mti - 1] ^ (mt[mti - 1] >> 30u)) + static_cast<uint32_t>(mti);
 85         }
 86         mag[0] = 0u;
 87         mag[1] = matrixA;
 88     }
 89     uint32_t GenRand()
 90     {
 91         uint32_t y = 0u;
 92         if (mti >= n)
 93         {
 94             int32_t kk;
 95             for (kk = 0; kk < n - m; ++kk)
 96             {
 97                 y = (mt[kk] & upperMask) | (mt[kk + 1] & lowerMask);
 98                 mt[kk] = mt[kk + m] ^ (y >> 1u) ^ mag[static_cast<int32_t>(y & 0x01u)];
 99             }
100             for (; kk < n - 1; ++kk)
101             {
102                 y = (mt[kk] & upperMask) | (mt[kk + 1] & lowerMask);
103                 mt[kk] = mt[kk + (m - n)] ^ (y >> 1u) ^ mag[static_cast<int32_t>(y & 0x01u)];
104             }
105             y = (mt[n - 1] & upperMask) | (mt[0] & lowerMask);
106             mt[n - 1] = mt[m - 1] ^ (y >> 1u) ^ mag[static_cast<int32_t>(y & 0x01u)];
107             mti = 0;
108         }
109         y = mt[mti++];
110         y = y ^ (y >> 11u);
111         y = y ^ ((y << 7u) & 0x9d2c5680u);
112         y = y ^ ((y << 15u) & 0xefc60000u);
113         y = y ^ (y >> 18u);
114         return y;
115     }
116 private:
117     bool initialized;
118     int32_t mti;
119     uint32_t mt[n];
120     uint32_t mag[2];
121 };
122 
123 MT::MT() : initialized(false)mti(0)mt()mag()
124 {
125 }
126 
127 #ifdef _WIN32
128 
129 
130 
131 #else
132 
133          MT* mt = nullptr;
134 
135 #endif
136 
137 void InitMt(uint32_t seed)
138 {
139     if (mt == nullptr)
140     {
141         mt = new MT();
142     }
143     mt->Init(seed);
144 }
145 
146 uint32_t Random()
147 {
148     if (mt == nullptr)
149     {
150         mt = new MT();
151     }
152     if (!mt->Initialized())
153     {
154         mt->InitWithRandomSeed();
155     }
156     return mt->GenRand();
157 }
158 
159 uint64_t Random64()
160 {
161     return static_cast<uint64_t>(Random()) << 32 | static_cast<uint64_t>(Random());
162 }
163 
164 } } // namespace cmajor::rt
165 
166 extern "C" void RtInitRand(uint32_t seed)
167 {
168     cmajor::rt::InitMt(seed);
169 }
170 
171 extern "C" uint32_t RtRandom()
172 {
173     return cmajor::rt::Random();
174 }
175 
176 extern "C" uint64_t RtRandom64()
177 {
178     return cmajor::rt::Random64();
179 }