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

Last change on this file since 3408 was 3408, checked in by ansari, 18 years ago

modifs commentaires pour doc par doxygen - Reza 23/11/2007

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