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

Last change on this file since 3612 was 3612, checked in by ansari, 16 years ago

Suite modifs / adaptation avec l'introduction de la suite des classes RandomGeneratorInterface et Cie , Reza 30/04/2009

File size: 8.1 KB
RevLine 
[3389]1#include "stsrand.h"
2#include "thsafeop.h"
[3403]3//#include "srandgen.h"
[3389]4#include "fiondblock.h"
5#include <math.h>
[3403]6#include <sys/time.h>
[3389]7
8namespace SOPHYA {
9
10/*!
[3612]11 \class STSRandGen
[3389]12 \ingroup BaseTools
[3408]13 \brief Random number generator
14
[3389]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
[3612]19 \sa SOPHYA::ObjFileIO<STSRandGen>
[3389]20
[3408]21 \sa frand01 drand01 frandpm1 drandpm1
22 \sa GauRnd PoissRand
23 \sa Ini_Ranf_Quick Ini_Ranf Get_Ranf Auto_Ini_Ranf
24
25
[3389]26*/
27
28// Objet statique global pour gestion de lock entre threads
29static ThSafeOp* ths_rand = NULL;
30
[3612]31STSRandGen::STSRandGen(size_t n, bool tsafe)
[3389]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
[3612]46STSRandGen::STSRandGen(STSRandGen const & rg)
[3389]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
[3599]60
[3612]61STSRandGen::~STSRandGen(void)
[3389]62{
63 // rien a faire
64}
65
[3612]66void STSRandGen::SetBuffSize(size_t n)
[3599]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
[3612]75void STSRandGen::AutoInit(int lp)
[3403]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 !
[3389]87{
[3403]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 }
[3612]135 if(lp>0) cout<<"STSRandGen::AutoInit: "<<seed_16v[0]<<" "<<seed_16v[1]<<" "<<seed_16v[2]<<endl;
[3403]136
137 // Initialise drand48()
138 Init(seed_16v,lp);
[3389]139}
140
[3612]141void STSRandGen::Init(long seed_val, int lp)
[3389]142{
143 if (ths_rand == NULL) ths_rand = new ThSafeOp;
[3612]144 if(lp) cout << "STSRandGen::Init(long seed=" << seed_val << ")" << endl;
[3389]145 ths_rand->lock();
146 srand48(seed_val);
147 ths_rand->unlock();
148 return;
149}
150
[3612]151void STSRandGen::Init(unsigned short seed_16v[3], int lp)
[3389]152{
153 if (ths_rand == NULL) ths_rand = new ThSafeOp;
[3612]154 if(lp) cout << "STSRandGen::Init(u_short seed_16v[3]=" << seed_16v[0]
[3389]155 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
156 ths_rand->lock();
157 Init_P(seed_16v);
158 ths_rand->unlock();
159}
160
[3612]161void STSRandGen::GetSeed(unsigned short seed_16v[3], int lp)
[3389]162{
163 if (ths_rand == NULL) ths_rand = new ThSafeOp;
164 ths_rand->lock();
165 GetSeed_P(seed_16v);
166 ths_rand->unlock();
[3612]167 if(lp) cout << "STSRandGen::GetSeed(u_short seed_16v[3]=" << seed_16v[0]
[3389]168 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
169 return;
170}
171
[3612]172void STSRandGen::Init_P(unsigned short seed_16v[3])
[3389]173{
174 seed48(seed_16v);
175}
176
[3612]177void STSRandGen::GetSeed_P(unsigned short seed_16v[3])
[3389]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
[3612]188r_8 STSRandGen::Gaussian()
[3389]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
[3612]196uint_8 STSRandGen::Poisson(double mu,double mumax)
[3389]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
[3612]220void STSRandGen::GenSeq(void)
[3389]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
[3612]230// ObjFileIO<STSRandGen>
[3389]231//----------------------------------------------------------
232
233/* --Methode-- */
234DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
[3612]235void ObjFileIO<STSRandGen>::WriteSelf(POutPersist& s) const
[3389]236{
237 if (dobj == NULL)
[3612]238 throw NullPtrError("ObjFileIO<STSRandGen>::WriteSelf() dobj=NULL");
[3389]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 */
[3612]261void ObjFileIO<STSRandGen>::ReadSelf(PInPersist& s)
[3389]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
[3612]270 if (dobj == NULL) dobj = new STSRandGen(sz, (sz>0)?true:false);
[3389]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__
[3612]290#pragma define_template ObjFileIO<STSRandGen>
[3389]291#endif
292
293#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
[3612]294template class ObjFileIO<STSRandGen>;
[3389]295#endif
296// ---------------------------------------------------------
297
298} /* namespace SOPHYA */
299
Note: See TracBrowser for help on using the repository browser.