Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
707 | werner | 1 | /******************************************************************************************** |
2 | ** iLand - an individual based forest landscape and disturbance model |
||
3 | ** http://iland.boku.ac.at |
||
4 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl |
||
5 | ** |
||
6 | ** This program is free software: you can redistribute it and/or modify |
||
7 | ** it under the terms of the GNU General Public License as published by |
||
8 | ** the Free Software Foundation, either version 3 of the License, or |
||
9 | ** (at your option) any later version. |
||
10 | ** |
||
11 | ** This program is distributed in the hope that it will be useful, |
||
12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | ** GNU General Public License for more details. |
||
15 | ** |
||
16 | ** You should have received a copy of the GNU General Public License |
||
17 | ** along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
18 | ********************************************************************************************/ |
||
19 | #include "randomgenerator.h" |
||
985 | werner | 20 | #include <QtGlobal> |
707 | werner | 21 | #include "../3rdparty/MersenneTwister.h" |
22 | |||
759 | werner | 23 | #include <QMutex> |
707 | werner | 24 | |
25 | class RGenerators |
||
26 | { |
||
27 | public: |
||
28 | RGenerators() {} |
||
29 | void seed(); |
||
30 | void seed(unsigned int oneSeed); |
||
31 | inline unsigned int random_function(const int type) { if (type==0) return WELLRNG512(); |
||
32 | if (type==1) return xorshf96(); |
||
33 | if (type==2) return fastrand(); |
||
34 | return 0; |
||
35 | } |
||
36 | private: |
||
37 | // see http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf |
||
38 | // for details on the WellRNG512 algorithm |
||
39 | inline unsigned long WELLRNG512(void); |
||
40 | /* initialize state to random bits */ |
||
41 | unsigned long state[16]; |
||
42 | /* init should also reset this to 0 */ |
||
43 | unsigned int index; |
||
44 | /* return 32 bit random number */ |
||
45 | |||
46 | int g_seed; |
||
47 | inline unsigned int fastrand() |
||
48 | { |
||
49 | g_seed = (214013*g_seed+2531011); |
||
50 | return g_seed; |
||
51 | } |
||
52 | unsigned long x,y,z; |
||
53 | unsigned long xorshf96(void); |
||
54 | |||
55 | }; |
||
56 | |||
57 | inline unsigned long RGenerators::WELLRNG512(void) |
||
58 | { |
||
59 | unsigned long a, b, c, d; |
||
60 | a = state[index]; |
||
61 | c = state[(index+13)&15]; |
||
62 | b = a^c^(a<<16)^(c<<15); |
||
63 | c = state[(index+9)&15]; |
||
64 | c ^= (c>>11); |
||
65 | a = state[index] = b^c; |
||
66 | d = a^((a<<5)&0xDA442D24UL); |
||
67 | index = (index + 15)&15; |
||
68 | a = state[index]; |
||
69 | state[index] = a^b^d^(a<<2)^(b<<18)^(c<<28); |
||
70 | return state[index]; |
||
71 | } |
||
72 | // The Marsaglia's xorshf generator: |
||
73 | // see: http://stackoverflow.com/questions/1640258/need-a-fast-random-generator-for-c and |
||
74 | // http://www.cse.yorku.ca/~oz/marsaglia-rng.html |
||
75 | //unsigned long x=123456789, y=362436069, z=521288629; |
||
76 | unsigned long RGenerators::xorshf96(void) { //period 2^96-1 |
||
77 | unsigned long t; |
||
78 | x ^= x << 16; |
||
79 | x ^= x >> 5; |
||
80 | x ^= x << 1; |
||
81 | |||
82 | t = x; |
||
83 | x = y; |
||
84 | y = z; |
||
85 | z = t ^ x ^ y; |
||
86 | |||
87 | return z; |
||
88 | } |
||
89 | |||
90 | |||
91 | inline void RGenerators::seed() |
||
92 | { |
||
93 | srand ( time(NULL) ); |
||
94 | for (int i=0;i<16;i++) |
||
95 | state[i] = std::rand(); |
||
96 | index = 0; |
||
97 | // inits for the xorshift algorithm... |
||
98 | x=123456789, y=362436069, z=521288629; |
||
99 | // inits for the fast rand.... |
||
100 | g_seed = std::rand(); |
||
101 | } |
||
102 | |||
103 | inline void RGenerators::seed(unsigned int oneSeed) |
||
104 | { |
||
105 | srand ( oneSeed ); |
||
106 | for (int i=0;i<16;i++) |
||
107 | state[i] = std::rand(); |
||
108 | index = 0; |
||
109 | x=123456789, y=362436069, z=521288629; |
||
110 | g_seed = oneSeed; |
||
111 | } |
||
112 | |||
113 | // static variables |
||
114 | unsigned int RandomGenerator::mBuffer[RANDOMGENERATORSIZE+5]; |
||
115 | int RandomGenerator::mIndex = 0; |
||
116 | int RandomGenerator::mRotationCount = RANDOMGENERATORROTATIONS + 1; |
||
758 | werner | 117 | int RandomGenerator::mRefillCounter = 0; |
707 | werner | 118 | RandomGenerator::ERandomGenerators RandomGenerator::mGeneratorType = RandomGenerator::ergFastRandom; |
119 | |||
120 | |||
121 | |||
122 | /// fill the internal buffer with random numbers choosen from the defined random generator |
||
757 | werner | 123 | QMutex random_generator_refill_mutex; |
124 | |||
707 | werner | 125 | void RandomGenerator::refill() { |
126 | |||
757 | werner | 127 | QMutexLocker lock(&random_generator_refill_mutex); // serialize access |
128 | if (mRotationCount<RANDOMGENERATORROTATIONS) // another thread might already succeeded in refilling.... |
||
129 | return; |
||
130 | |||
707 | werner | 131 | RGenerators gen; |
132 | gen.seed(mBuffer[RANDOMGENERATORSIZE+4]); // use the last value as seed for the next round.... |
||
133 | switch (mGeneratorType) { |
||
134 | case ergMersenneTwister: { |
||
135 | MTRand mersenne; |
||
757 | werner | 136 | // qDebug() << "refill random numbers. seed" <<mBuffer[RANDOMGENERATORSIZE+4]; |
707 | werner | 137 | mersenne.seed(mBuffer[RANDOMGENERATORSIZE+4]); |
757 | werner | 138 | //mersenne.seed(); // use random number seed from mersenne twister (hash of time and clock) |
707 | werner | 139 | for (int i=0;i<RANDOMGENERATORSIZE+5;++i) |
140 | mBuffer[i] = mersenne.randInt(); |
||
141 | break; |
||
142 | } |
||
143 | case ergWellRNG512: { |
||
144 | |||
145 | for (int i=0;i<RANDOMGENERATORSIZE+5;++i) |
||
146 | mBuffer[i] = gen.random_function(0); |
||
147 | break; |
||
148 | } |
||
149 | case ergXORShift96: { |
||
150 | for (int i=0;i<RANDOMGENERATORSIZE+5;++i) |
||
151 | mBuffer[i] = gen.random_function(1); |
||
152 | break; |
||
153 | } |
||
154 | case ergFastRandom: { |
||
155 | for (int i=0;i<RANDOMGENERATORSIZE+5;++i) |
||
156 | mBuffer[i] = gen.random_function(2); |
||
157 | break; |
||
158 | } |
||
159 | } // switch |
||
160 | |||
161 | |||
162 | mIndex = 0; // reset the index |
||
757 | werner | 163 | mRotationCount=0; |
758 | werner | 164 | mRefillCounter++; |
707 | werner | 165 | } |
166 | |||
167 | void RandomGenerator::seed(const unsigned oneSeed) |
||
168 | { |
||
169 | if (oneSeed==0) { |
||
170 | srand ( time(NULL) ); |
||
171 | mBuffer[RANDOMGENERATORSIZE+4] = std::rand(); |
||
172 | } else { |
||
173 | mBuffer[RANDOMGENERATORSIZE+4] = oneSeed; // set a specific seed as seed for the next round |
||
174 | } |
||
175 | } |