Subversion Repositories public iLand

Rev

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
}