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

Last change on this file since 3840 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
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
[3389]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
[3612]20 \sa SOPHYA::ObjFileIO<STSRandGen>
[3389]21
[3408]22 \sa frand01 drand01 frandpm1 drandpm1
23 \sa GauRnd PoissRand
24 \sa Ini_Ranf_Quick Ini_Ranf Get_Ranf Auto_Ini_Ranf
25
26
[3389]27*/
28
29// Objet statique global pour gestion de lock entre threads
30static ThSafeOp* ths_rand = NULL;
31
[3612]32STSRandGen::STSRandGen(size_t n, bool tsafe)
[3389]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
[3612]47STSRandGen::STSRandGen(STSRandGen const & rg)
[3389]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
[3599]61
[3612]62STSRandGen::~STSRandGen(void)
[3389]63{
64 // rien a faire
65}
66
[3612]67void STSRandGen::SetBuffSize(size_t n)
[3599]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
[3612]76void STSRandGen::AutoInit(int lp)
[3403]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 !
[3389]88{
[3403]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 }
[3612]136 if(lp>0) cout<<"STSRandGen::AutoInit: "<<seed_16v[0]<<" "<<seed_16v[1]<<" "<<seed_16v[2]<<endl;
[3403]137
138 // Initialise drand48()
139 Init(seed_16v,lp);
[3389]140}
141
[3612]142void STSRandGen::Init(long seed_val, int lp)
[3389]143{
144 if (ths_rand == NULL) ths_rand = new ThSafeOp;
[3612]145 if(lp) cout << "STSRandGen::Init(long seed=" << seed_val << ")" << endl;
[3389]146 ths_rand->lock();
147 srand48(seed_val);
148 ths_rand->unlock();
149 return;
150}
151
[3612]152void STSRandGen::Init(unsigned short seed_16v[3], int lp)
[3389]153{
154 if (ths_rand == NULL) ths_rand = new ThSafeOp;
[3612]155 if(lp) cout << "STSRandGen::Init(u_short seed_16v[3]=" << seed_16v[0]
[3389]156 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
157 ths_rand->lock();
158 Init_P(seed_16v);
159 ths_rand->unlock();
160}
161
[3612]162void STSRandGen::GetSeed(unsigned short seed_16v[3], int lp)
[3389]163{
164 if (ths_rand == NULL) ths_rand = new ThSafeOp;
165 ths_rand->lock();
166 GetSeed_P(seed_16v);
167 ths_rand->unlock();
[3612]168 if(lp) cout << "STSRandGen::GetSeed(u_short seed_16v[3]=" << seed_16v[0]
[3389]169 << "," << seed_16v[1] << "," << seed_16v[2] << ")" << endl;
170 return;
171}
172
[3612]173void STSRandGen::Init_P(unsigned short seed_16v[3])
[3389]174{
175 seed48(seed_16v);
176}
177
[3612]178void STSRandGen::GetSeed_P(unsigned short seed_16v[3])
[3389]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
[3612]189r_8 STSRandGen::Gaussian()
[3389]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
[3612]197uint_8 STSRandGen::Poisson(double mu,double mumax)
[3389]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
[3612]221void STSRandGen::GenSeq(void)
[3389]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
[3612]231// ObjFileIO<STSRandGen>
[3389]232//----------------------------------------------------------
233
234/* --Methode-- */
235DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
[3612]236void ObjFileIO<STSRandGen>::WriteSelf(POutPersist& s) const
[3389]237{
238 if (dobj == NULL)
[3612]239 throw NullPtrError("ObjFileIO<STSRandGen>::WriteSelf() dobj=NULL");
[3389]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 */
[3612]262void ObjFileIO<STSRandGen>::ReadSelf(PInPersist& s)
[3389]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
[3612]271 if (dobj == NULL) dobj = new STSRandGen(sz, (sz>0)?true:false);
[3389]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__
[3612]291#pragma define_template ObjFileIO<STSRandGen>
[3389]292#endif
293
294#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
[3612]295template class ObjFileIO<STSRandGen>;
[3389]296#endif
297// ---------------------------------------------------------
298
299} /* namespace SOPHYA */
300
Note: See TracBrowser for help on using the repository browser.