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

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

add various #include<> for g++ 4.3 (jaunty 9.04), cmv 05/05/2009

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