source: Sophya/trunk/SophyaLib/BaseTools/stsrand.cc@ 3603

Last change on this file since 3603 was 3599, checked in by cmv, 16 years ago

redimensionnement du buffer RandomGenerator, cmv 22/04/2009

File size: 8.2 KB
Line 
1#include "stsrand.h"
2#include "thsafeop.h"
3//#include "srandgen.h"
4#include "fiondblock.h"
5#include <math.h>
6#include <sys/time.h>
7
8namespace SOPHYA {
9
10/*!
11 \class RandomGenerator
12 \ingroup BaseTools
13 \brief Random number generator
14
15 This class is a thread-safe random number generator.
16 Its PPF handler can be used to save the complete state of the class and the underlying
17 random number generator used.
18
19 \sa SOPHYA::ObjFileIO<RandomGenerator>
20
21 \sa frand01 drand01 frandpm1 drandpm1
22 \sa GauRnd PoissRand
23 \sa Ini_Ranf_Quick Ini_Ranf Get_Ranf Auto_Ini_Ranf
24
25
26*/
27
28// Objet statique global pour gestion de lock entre threads
29static ThSafeOp* ths_rand = NULL;
30
31RandomGenerator::RandomGenerator(size_t n, bool tsafe)
32{
33 if (ths_rand == NULL) ths_rand = new ThSafeOp;
34 if (tsafe) { // thread-safe
35 fg_nothrsafe = false;
36 if (n < 1) n = 1024;
37 rseq_.ReSize(n, false);
38 idx_ = n;
39 }
40 else { // NOT thread-safe
41 fg_nothrsafe = true;
42 idx_ = 1;
43 }
44}
45
46RandomGenerator::RandomGenerator(RandomGenerator const & rg)
47{
48 if (ths_rand == NULL) ths_rand = new ThSafeOp;
49 if (!rg.fg_nothrsafe) { // thread-safe
50 fg_nothrsafe = false;
51 rseq_.ReSize(rg.rseq_.Size(), false);
52 idx_ = rseq_.Size();
53 }
54 else { // NOT thread-safe
55 fg_nothrsafe = true;
56 idx_ = 1;
57 }
58}
59
60
61RandomGenerator::~RandomGenerator(void)
62{
63 // rien a faire
64}
65
66void RandomGenerator::SetBuffSize(size_t n)
67// redimensionnement du buffer
68{
69 if(fg_nothrsafe) return;
70 if (n < 1) n = 1024;
71 rseq_.ReSize(n, false);
72 idx_ = n;
73}
74
75void RandomGenerator::AutoInit(int lp)
76// Initialisation automatique (pseudo) aleatoire du generateur.
77// L'initialiseur est donne par un codage du nombre de millisecondes
78// ecoulees depuis le 0 heure le 1er Janvier 1970 UTC (cf gettimeofday).
79// Seuls les 48 bits de poids faible sont retenus.
80// Un melange des bits est ensuite effectue pour que les 3 nombres
81// (unsigned short) d'initialisation ne soient pas trop semblables.
82//
83// Le nombre le plus grand que l'on peut mettre
84// dans un entier unsigned de N bits est: 2^N-1
85// 48 bits -> 2^48-1 = 281474976710655 musec = 3257.8j = 8.9y
86// -> meme initialisation tous les 8.9 ans a 1 microsec pres !
87{
88 // On recupere le temps ecoule depuis l'origine code en sec+musec
89 struct timeval now;
90 gettimeofday(&now,0);
91
92 // Calcul du temps ecoule depuis l'origine en microsecondes
93 uint_8 v = (uint_8)now.tv_sec*(uint_8)1000000 + (uint_8)now.tv_usec;
94 if(lp>1) cout<<"..."<<now.tv_sec<<" sec + "<<now.tv_usec<<" musec = "<<v<<" musec"<<endl;
95
96 // Remplissage du tableau de bits
97 unsigned short b[48];
98 for(int ip=0;ip<48;ip++) {b[ip] = v&1; v = (v>>1);}
99 if(lp>2) {
100 cout<<"...b= ";
101 for(int ip=47;ip>=0;ip--) {if(ip==23) cout<<" "; cout<<b[ip];}
102 cout<<endl;
103 }
104
105 // Melange des bits qui varient vite (poids faible, microsec)
106 // avec ceux variant lentement (poids fort, sec)
107 // On coupe le mot en trois: bits[0-15], bits[16-31] et bits[32-47]
108 // On echange 2 bits sur 3 du mot bits[0-15] dans les autres mots
109 // bit0 <-> bit0 , bit1 <-> bit17 , bit2 <-> bit34
110 // bit3 <-> bit3 , bit4 <-> bit20 , bit5 <-> bit37
111 // bit13 <-> bit13 , bit14 <-> bit30 , bit15 <-> bit47
112 for(int ip=0;ip<16;ip++) {
113 if(ip%3==0) continue;
114 int ipd = (ip%3==1)? 16+ip : 32+ip;
115 unsigned short w = b[ip];
116 //cout<<"swap g["<<ip<<"]="<<b[ip]<<" <-> b["<<ipd<<"]="<<b[ipd]<<endl;
117 b[ip] = b[ipd];
118 b[ipd] = w;
119 }
120 if(lp>2) {
121 cout<<"...b= ";
122 for(int ip=47;ip>=0;ip--) {if(ip==23) cout<<" "; cout<<b[ip];}
123 cout<<endl;
124 }
125
126 // Construction du tableau d'initialisation
127 unsigned short seed_16v[3] = {0,0,0};
128 for(int is=0;is<3;is++) {
129 unsigned short w = 1;
130 for(int ip=0;ip<16;ip++) {
131 seed_16v[is] += w*b[is*16+ip];
132 w *= 2;
133 }
134 }
135 if(lp>0) cout<<"RandomGenerator::AutoInit: "<<seed_16v[0]<<" "<<seed_16v[1]<<" "<<seed_16v[2]<<endl;
136
137 // Initialise drand48()
138 Init(seed_16v,lp);
139}
140
141void RandomGenerator::Init(long seed_val, int lp)
142{
143 if (ths_rand == NULL) ths_rand = new ThSafeOp;
144 if(lp) cout << "RandomGenerator::Init(long seed=" << seed_val << ")" << endl;
145 ths_rand->lock();
146 srand48(seed_val);
147 ths_rand->unlock();
148 return;
149}
150
151void RandomGenerator::Init(unsigned short seed_16v[3], int lp)
152{
153 if (ths_rand == NULL) ths_rand = new ThSafeOp;
154 if(lp) cout << "RandomGenerator::Init(u_short seed_16v[3]=" << seed_16v[0]
155 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
156 ths_rand->lock();
157 Init_P(seed_16v);
158 ths_rand->unlock();
159}
160
161void RandomGenerator::GetSeed(unsigned short seed_16v[3], int lp)
162{
163 if (ths_rand == NULL) ths_rand = new ThSafeOp;
164 ths_rand->lock();
165 GetSeed_P(seed_16v);
166 ths_rand->unlock();
167 if(lp) cout << "RandomGenerator::GetSeed(u_short seed_16v[3]=" << seed_16v[0]
168 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
169 return;
170}
171
172void RandomGenerator::Init_P(unsigned short seed_16v[3])
173{
174 seed48(seed_16v);
175}
176
177void RandomGenerator::GetSeed_P(unsigned short seed_16v[3])
178{
179 unsigned short seed[3] = {0,0,0};
180 unsigned short *p;
181 p = seed48(seed);
182 memcpy(seed_16v,p,3*sizeof(unsigned short));
183 /* on re-initialise a ce qui etait avant */
184 seed48(seed_16v);
185 return;
186}
187
188r_8 RandomGenerator::Gaussian()
189{
190 r_8 A=Next();
191 while (A==0.) A=Next();
192 return sqrt(-2.*log(A))*cos(2.*M_PI*Next());
193}
194
195
196uint_8 RandomGenerator::Poisson(double mu,double mumax)
197{
198 double pp,ppi,x;
199
200 if((mumax>0.)&&(mu>=mumax)) {
201 pp = sqrt(mu);
202 while( (x=pp*Gaussian()) < -mu );
203 return (uint_8)(mu+x+0.5);
204 }
205 else {
206 uint_8 n;
207 ppi = pp = exp(-mu);
208 x = Next();
209 n = 0;
210 while (x > ppi) {
211 n++;
212 pp = mu*pp/(double)n;
213 ppi += pp;
214 }
215 return n;
216 }
217 return 0; // pas necessaire ?
218}
219
220void RandomGenerator::GenSeq(void)
221{
222 ths_rand->lock();
223 for(size_t k=0; k<rseq_.Size(); k++) rseq_(k) = drand48();
224 ths_rand->unlock();
225 idx_ = 0;
226}
227
228//----------------------------------------------------------
229// Classe pour la gestion de persistance
230// ObjFileIO<RandomGenerator>
231//----------------------------------------------------------
232
233/* --Methode-- */
234DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
235void ObjFileIO<RandomGenerator>::WriteSelf(POutPersist& s) const
236{
237 if (dobj == NULL)
238 throw NullPtrError("ObjFileIO<RandomGenerator>::WriteSelf() dobj=NULL");
239 ths_rand->lock(); // thread-safety
240 uint_4 itab[6];
241 //itab : [0]: version, [1,2,3] = srand48 state/seed , [4,5] = reserved for future use
242 itab[0] = 1;
243 // On recupere et on ecrit ds le PPF l'etat du generateur aleatoire
244 unsigned short seed_16v[3];
245 dobj->GetSeed_P(seed_16v);
246 for(int i=0; i<3; i++) itab[i+1] = seed_16v[i];
247 itab[4] = 0;
248 s.Put(itab, 6);
249 uint_8 sz = dobj->rseq_.Size();
250 s.Put(sz); // Taille du tableau intermediaire
251 uint_8 ix = dobj->idx_;
252 s.Put(ix); // valeur de l'index
253
254 if (dobj->rseq_.Size() > 0) s << dobj->rseq_; // On ecrit le tableau (NDataBlock) si necessaire
255 ths_rand->unlock(); // thread-safety
256 return;
257}
258
259/* --Methode-- */
260DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
261void ObjFileIO<RandomGenerator>::ReadSelf(PInPersist& s)
262{
263 uint_4 itab[6];
264 //itab : [0]: version, [1,2,3] = srand48 state/seed , [4] = reserved for future use
265 s.Get(itab, 6);
266 uint_8 sz,ix;
267 s.Get(sz); // Taille du tableau intermediaire
268 s.Get(ix); // Taille du tableau intermediaire
269
270 if (dobj == NULL) dobj = new RandomGenerator(sz, (sz>0)?true:false);
271 dobj->idx_ = ix;
272 if (sz > 0) {
273 s >> dobj->rseq_; // On lit le tableau (NDataBlock) si necessaire
274 dobj->fg_nothrsafe = false;
275 }
276 else { // Objet lu est NON thread-safe, taille_tableau rseq_ = 0
277 dobj->fg_nothrsafe = true;
278 if (dobj->rseq_.Size() > 0) dobj->rseq_.Dealloc();
279 }
280 // On initialise l'etat du generateur aleatoire avec les valeurs lues
281 unsigned short seed_16v[3];
282 dobj->GetSeed_P(seed_16v);
283 for(int i=0; i<3; i++) seed_16v[i] = itab[i+1];
284 dobj->Init(seed_16v, 0);
285 return;
286}
287
288// ---------------------------------------------------------
289#ifdef __CXX_PRAGMA_TEMPLATES__
290#pragma define_template ObjFileIO<RandomGenerator>
291#endif
292
293#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
294template class ObjFileIO<RandomGenerator>;
295#endif
296// ---------------------------------------------------------
297
298} /* namespace SOPHYA */
299
Note: See TracBrowser for help on using the repository browser.