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

Last change on this file since 3403 was 3403, checked in by cmv, 18 years ago

nouvel algo pour AutoIni de RandomGene , cmv 23/11/2007

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