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

Last change on this file since 4085 was 3889, checked in by ansari, 15 years ago

correction bug SetSeed() ds ThSDR48RandGen + retag en V2_2, Reza 27/09/2010

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