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

Last change on this file since 3889 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
Line 
1#include "stsrand.h"
2#include "thsafeop.h"
3//#include "srandgen.h"
4#include "fiondblock.h"
5#include <string.h>
6#include <math.h>
7#include <sys/time.h>
8
9namespace SOPHYA {
10
11/*!
12 \class STSRandGen
13 \ingroup BaseTools
14 \brief Random number generator
15
16 \warning This class is OBSOLETE. Use ThSDR48RandGen instead.
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
21 \sa SOPHYA::ObjFileIO<STSRandGen>
22
23 \sa frand01 drand01 frandpm1 drandpm1
24 \sa GauRnd PoissRand
25 \sa Ini_Ranf_Quick Ini_Ranf Get_Ranf Auto_Ini_Ranf
26
27
28*/
29
30// Objet statique global pour gestion de lock entre threads
31static ThSafeOp* ths_rand = NULL;
32
33STSRandGen::STSRandGen(size_t n, bool tsafe)
34{
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
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
51STSRandGen::STSRandGen(STSRandGen const & rg)
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
65
66STSRandGen::~STSRandGen(void)
67{
68 // rien a faire
69}
70
71void STSRandGen::SetBuffSize(size_t n)
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
80void STSRandGen::AutoInit(int lp)
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 !
92{
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 }
140 if(lp>0) cout<<"STSRandGen::AutoInit: "<<seed_16v[0]<<" "<<seed_16v[1]<<" "<<seed_16v[2]<<endl;
141
142 // Initialise drand48()
143 Init(seed_16v,lp);
144}
145
146void STSRandGen::Init(long seed_val, int lp)
147{
148 if (ths_rand == NULL) ths_rand = new ThSafeOp;
149 if(lp) cout << "STSRandGen::Init(long seed=" << seed_val << ")" << endl;
150 ths_rand->lock();
151 srand48(seed_val);
152 ths_rand->unlock();
153 return;
154}
155
156void STSRandGen::Init(unsigned short seed_16v[3], int lp)
157{
158 if (ths_rand == NULL) ths_rand = new ThSafeOp;
159 if(lp) cout << "STSRandGen::Init(u_short seed_16v[3]=" << seed_16v[0]
160 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
161 ths_rand->lock();
162 Init_P(seed_16v);
163 ths_rand->unlock();
164}
165
166void STSRandGen::GetSeed(unsigned short seed_16v[3], int lp)
167{
168 if (ths_rand == NULL) ths_rand = new ThSafeOp;
169 ths_rand->lock();
170 GetSeed_P(seed_16v);
171 ths_rand->unlock();
172 if(lp) cout << "STSRandGen::GetSeed(u_short seed_16v[3]=" << seed_16v[0]
173 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
174 return;
175}
176
177void STSRandGen::Init_P(unsigned short seed_16v[3])
178{
179 seed48(seed_16v);
180}
181
182void STSRandGen::GetSeed_P(unsigned short seed_16v[3])
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
193r_8 STSRandGen::Gaussian()
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
201uint_8 STSRandGen::Poisson(double mu,double mumax)
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
225void STSRandGen::GenSeq(void)
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
235// ObjFileIO<STSRandGen>
236//----------------------------------------------------------
237
238/* --Methode-- */
239DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
240void ObjFileIO<STSRandGen>::WriteSelf(POutPersist& s) const
241{
242 if (dobj == NULL)
243 throw NullPtrError("ObjFileIO<STSRandGen>::WriteSelf() dobj=NULL");
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 */
266void ObjFileIO<STSRandGen>::ReadSelf(PInPersist& s)
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
275 if (dobj == NULL) dobj = new STSRandGen(sz, (sz>0)?true:false);
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__
295#pragma define_template ObjFileIO<STSRandGen>
296#endif
297
298#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
299template class ObjFileIO<STSRandGen>;
300#endif
301// ---------------------------------------------------------
302
303} /* namespace SOPHYA */
304
Note: See TracBrowser for help on using the repository browser.