source: Sophya/trunk/SophyaLib/BaseTools/srandgen.c@ 3408

Last change on this file since 3408 was 3408, checked in by ansari, 18 years ago

modifs commentaires pour doc par doxygen - Reza 23/11/2007

File size: 16.3 KB
Line 
1#include "machdefs.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <math.h>
6#include <sys/time.h>
7#include "srandgen.h"
8#include "smathconst.h"
9
10static double GAU_RANGE=6.;
11
12/*
13++
14 Module Tirages aleatoires (C)
15 Lib LibsUtil
16 include srandgen.h
17--
18*/
19
20/*
21++
22 frand01()
23 tirage aleatoire entre 0 et 1, retourne float
24 drand01()
25 tirage aleatoire entre 0 et 1, retourne double
26 rand01()
27 c'est le defaut: drand01()
28 frandpm1()
29 tirage aleatoire entre -1 et 1, retourne float
30 drandpm1()
31 tirage aleatoire entre -1 et 1, retourne double
32 ranfpm1()
33 c'est le defaut: drandpm1()
34--
35*/
36
37/*! \ingroup BaseTools
38 \fn frand01
39 Returns a random number (float) with flat distribution between 0 ... 1
40*/
41/*! \ingroup BaseTools
42 \fn drand01
43 Returns a random number (double) with flat distribution between 0 ... 1
44*/
45/*! \ingroup BaseTools
46 \fn frandpm1()
47 Returns a random number (float) with flat distribution between -1 ... 1
48*/
49/*! \ingroup BaseTools
50 \fn drandpm1()
51 Returns a random number (double) with flat distribution between -1 ... 1
52*/
53
54/*=========================================================================*/
55/*
56++
57 void Ini_Ranf_Quick(long seed_val, int lp)
58 Initialisation rapide du generateur (drand48) par un entier
59 de 32 bits de type long (cf srand48).
60--
61*/
62
63/*! \ingroup BaseTools
64 Fast initialisation of the random number generator \c (drand48)
65 using a \c long type value (cf \c srand48 )
66*/
67void Ini_Ranf_Quick(long seed_val, int lp)
68{
69if(lp) printf("Ini_Ranf_Quick: %d\n",(int) seed_val);
70srand48(seed_val);
71return;
72}
73
74/*=========================================================================*/
75/*
76++
77 void Ini_Ranf(unsigned short seed_16v[3], int lp)
78 Initialisation complete du generateur (drand48) par
79 48 bits (cf seed48).
80--
81*/
82/*! \ingroup BaseTools
83 complete initialisation of the random number generator \c (drand48)
84 using a \c using 48 bits (cf \c seed48 )
85*/
86void Ini_Ranf(unsigned short seed_16v[3], int lp)
87{
88if(lp) printf("Ini_Ranf: %d %d %d\n"
89 ,seed_16v[0],seed_16v[1],seed_16v[2]);
90seed48(seed_16v);
91return;
92}
93
94/*=========================================================================*/
95/*
96++
97 void Get_Ranf(unsigned short seed_16v[3], int lp)
98 Recuperation de l'etat du generateur (drand48) sur
99 de 48 bits (cf seed48).
100--
101*/
102/*! \ingroup BaseTools
103 Returns the status (48 bits) of the random number generator \c (drand48)
104 (cf \c seed48 )
105*/
106void Get_Ranf(unsigned short seed_16v[3], int lp)
107{
108unsigned short seed[3] = {0,0,0};
109unsigned short *p;
110p = seed48(seed);
111memcpy(seed_16v,p,3*sizeof(unsigned short));
112if(lp) printf("Get_Ranf: %d %d %d\n"
113 ,seed_16v[0],seed_16v[1],seed_16v[2]);
114/* on re-initialise a ce qui etait avant */
115seed48(seed_16v);
116return;
117}
118
119/*=========================================================================*/
120/*
121++
122 void Auto_Ini_Ranf(int lp)
123 Initialisation automatique (pseudo) aleatoire du generateur.
124 L'initialiseur est donne par le nombre de millisecondes
125 ecoulees depuis le dernier jour multiple de 23 du nombre de jours
126 depuis le 0 heure le 1er Janvier 1970 UTC (cf gettimeofday).
127 Pour retomber sur la meme initialisation
128 il faut generer deux aleatoires a moins de 1/1000 seconde
129 ou generer le deuxieme aleatoire 23 jours apres le premier
130 a la meme heure (a 1/1000 de seconde pres). La fonction
131 d'initialisation utilisee est Ini_Ranf_Quick(long).
132--
133*/
134/*! \ingroup BaseTools
135 Automatic initialisation using the present time
136*/
137void Auto_Ini_Ranf(int lp)
138{
139struct timeval now;
140long nj,nj23,seed=0;
141double buf;
142
143gettimeofday (&now,0);
144
145/* dans 32 bits signes on met environ 23 jours a 1/1000 de seconde pres! */
146/* Nombre de jours depuis l'origine */
147nj = (long) now.tv_sec / 86400;
148/* Nombre de jours depuis le dernier jour multiple de 23 jours */
149nj23 = nj % 23;
150/* nombre de secondes depuis le dernier jour multiple de 23 jours */
151buf = (double) (nj23*86400 + (now.tv_sec-nj*86400));
152/* nombre de milliemes de secondes depuis ... */
153buf = buf*1000. + now.tv_usec/1000.;
154seed = (long) buf;
155
156if(lp) {
157 printf("Auto_Ini_Ranf: date %ld s %ld 10^-6 sec seed=%ld:\n"
158 ,(long)now.tv_sec,(long)now.tv_usec,seed);
159 if(lp>1) printf("... njours=%ld nj23=%ld buf=%.20g\n",nj,nj23,buf);
160}
161Ini_Ranf_Quick(seed,lp);
162return;
163}
164
165/*=========================================================================*/
166/*
167++
168 void SetGauRange(double range)
169 Generation de distribution gaussienne:
170 Changement de l'initialisation de l'excursion du tirage
171 en nombre de sigmas (obsolete).
172--
173*/
174void SetGauRange(double range)
175{
176GAU_RANGE = range;
177}
178
179/*=========================================================================*/
180/*
181++
182 float NorRand(void)
183 Generation aleatoire gaussienne normee centree
184--
185*/
186/*! \ingroup BaseTools
187 Normal (Gaussian) random number generator (Mean=0., Sigma=1.)
188*/
189float NorRand(void)
190{
191double x,A,B;
192
193LAB10:
194A = drand01();
195if ( A == 0. ) goto LAB10;
196B = drand01();
197x = sqrt(-2.*log(A))*cos(DeuxPi*B);
198return( (float) x );
199}
200
201/*=========================================================================*/
202/*
203++
204 float NorRand1(void)
205 Generation aleatoire gaussienne normee centree
206 la distribution est limitee entre +/- GAU_RANGE (obsolete).
207--
208*/
209float NorRand1(void)
210{
211double b, x, y, gauss;
212
213b = 1./sqrt(2.*M_PI);
214LAB10:
215x = GAU_RANGE*drandpm1();
216y = drand01()*b;
217gauss = b*exp(-x*x/2.);
218if ( gauss-y < 0. ) goto LAB10 ;
219return( (float) x );
220}
221
222/*=========================================================================*/
223/*
224++
225 double GauRnd(double am, double s)
226 Generation aleatoire gaussienne de centre "am" et de sigma "s".
227--
228*/
229/*! \ingroup BaseTools
230 Normal (Gaussian) random number generator with the specified mean
231 (\c am ) and sigma (\c s )
232*/
233double GauRnd(double am, double s)
234{
235double x,A,B;
236
237LAB10:
238A = drand01();
239if ( A == 0. ) goto LAB10;
240B = drand01();
241x = am + s * sqrt(-2.*log(A))*cos(DeuxPi*B);
242return(x);
243}
244
245/*! \ingroup BaseTools
246 \brief Poisson random number generator.
247
248 Return an integer value (>=0) corresponding a Poisson distribution with mean \b mu.
249 \warning NOT the most efficient way of generating a large series of numbers
250 with the SAME mean
251*/
252int PoissRand(double mu)
253{
254 double pp,ppi,x;
255 int n;
256 ppi = pp = exp(-mu);
257 x = drand01();
258 n = 0;
259 while (x > ppi) {
260 n++;
261 pp = mu*pp/(double)n;
262 ppi += pp;
263 }
264 return n;
265}
266
267/*! \ingroup BaseTools
268 \brief Poisson random number generator with approximation for large mean.
269
270 Return an integer value (>=0) corresponding a Poisson distribution with mean \b mu.
271 If \b mu is greater or equal than \b mumax,
272 the large number gaussian approximation is applied.
273 \b mumax=10 is a good value.
274*/
275unsigned long PoissRandLimit(double mu,double mumax)
276// p(n) = (mu^n / n!) exp(-mu) for n = 0, 1, 2, ...
277{
278 double pp,ppi,x;
279 unsigned long n;
280
281 if(mu>=mumax) {
282 pp = sqrt(mu);
283 while( (x=pp*NorRand()) < -mu );
284 return (unsigned long)(mu+x+0.5);
285 }
286
287 ppi = pp = exp(-mu);
288 x = drand01();
289 n = 0;
290 while (x > ppi) {
291 n++;
292 pp = mu*pp/(double)n;
293 ppi += pp;
294 }
295 return n;
296}
297
298/*=========================================================================*/
299/*
300++
301 double GauRnd1(double am, double s)
302 Generation aleatoire gaussienne de centre "am" et de
303 sigma "s" la distribution est limitee entre am +/- GAU_RANGE (obsolete).
304--
305*/
306/*! \ingroup BaseTools
307 \brief OBSOLETE (gaussian random number generator)
308*/
309double GauRnd1(double am, double s)
310{
311double s2, b, x, y, gauss;
312
313s2 = 2.*s*s;
314b = 1./sqrt(2.*M_PI*s);
315LAB10:
316x = am + GAU_RANGE*s*drandpm1();
317y = drand01()*b;
318gauss = b*exp(-(x-am)*(x-am)/s2);
319if ( gauss-y < 0. ) goto LAB10 ;
320return(x);
321}
322
323/*==========================================================================*/
324/*
325++
326 void NormGau(double *x,double *y,double mx,double my,double sa,double sb,double teta);
327 Tirage de 2 nombres aleatoires x et y distribues sur une gaussienne 2D
328 de centre (x=mx,y=my), de sigmas grand axe et petit axe (sa,sb)
329 et dont le grand axe fait un angle teta (radian) avec l'axe des x.
330--
331*/
332/*
333++
334| - La densite de probabilite (normalisee a 1) sur laquelle on tire est:
335| N*exp[-0.5*{ (A/sa)**2+(C/sc)**2 }], N=1/(2Pi*sa*sc)
336| ou A et B sont les coordonnees selon le grand axe et le petit axe
337| et teta = angle(x,A), le resultat subit ensuite une rotation d'angle teta.
338| - La matrice des covariances C des variables A,B est:
339| | sa^2 0 |
340| | | et det(C) = (1-ro^2)*sa^2*sb^2
341| | 0 sb^2 |
342| - La distribution x,y resultante est:
343| N*exp[-0.5*{[(dx/sx)^2-2*ro/(sx*sy)*dx*dy+(dy/sy)^2]/(1-ro^2)}]
344| ou N est donne dans NormCo et sx,sy,ro sont calcules a partir
345| de sa,sc,teta (voir fonctions paramga ou gaparam). La matrice des
346| covariances des variables x,y est donnee dans la fonction NormCo.
347--
348*/
349void NormGau(double *x,double *y
350 ,double mx,double my,double sa,double sb,double teta)
351{
352double c,s,X,Y;
353
354LAB10:
355 s = drand01();
356 if ( s == 0. ) goto LAB10;
357s = sqrt(-2.*log(s));
358c = DeuxPi * drand01();
359
360X = sa*s*cos(c);
361Y = sb*s*sin(c);
362
363c = cos(teta); s = sin(teta);
364*x = mx + c*X - s*Y;
365*y = my + s*X + c*Y;
366}
367
368/*==========================================================================*/
369/*
370++
371 int NormCo(double *x,double *y,double mx,double my,double sx,double sy,double ro)
372 Tirage de 2 nombres aleatoires x et y distribues sur une gaussienne 2D
373 de centre (mx,my), de coefficient de correlation rho (ro) et telle que
374 les sigmas finals des variables x et y soient sx,sy (ce sont
375 les valeurs des distributions marginales des variables aleatoires x et y
376 c'est a dire les sigmas des projections x et y de l'histogramme 2D
377 de la gaussienne). Retourne 0 si ok.
378--
379*/
380/*
381++
382| - La densite de probabilite (normalisee a 1) sur laquelle on tire est:
383| N*exp[-0.5*{[(dx/sx)^2-2*ro/(sx*sy)*dx*dy+(dy/sy)^2]/(1-ro^2)}]
384| avec dx = x-mx, dy = y-my et N = 1/[2Pi*sx*sy*sqrt(1-ro^2)]
385| - Dans ce cas la distribution marginale est (ex en X):
386| 1/(sqrt(2Pi)*sx) * exp[-0.5*{dx^2/sx^2}]
387| - La matrice des covariances C des variables x,y est:
388| | sx^2 ro*sx*sy |
389| | | et det(C) = (1-ro^2)*sx^2*sy^2
390| | ro*sx*sy sy^2 |
391| - La matrice inverse C^(-1) est:
392| | 1/sx^2 -ro/(sx*sy) |
393| | | * 1/(1-ro^2)
394| | -ro/(sx*sy) 1/sy^2 |
395--
396*/
397/*
398++
399| - Remarque:
400| le sigma que l'on obtient quand on fait une coupe de la gaussienne 2D
401| en y=0 (ou x=0) est: SX0(y=0) = sx*sqrt(1-ro^2) different de sx
402| SY0(x=0) = sy*sqrt(1-ro^2) different de sy
403| La distribution qui correspond a des sigmas SX0,SY0
404| pour les coupes en y=0,x=0 de la gaussienne 2D serait:
405| N*exp[-0.5*{ (dx/SX0)^2-2*ro/(SX0*SY0)*dx*dy+(dy/SY0)^2 }]
406| avec N = sqrt(1-ro^2)/(2Pi*SX0*SY0) et les variances
407| des variables x,y sont toujours
408| sx=SX0/sqrt(1-ro^2), sy=SY0/sqrt(1-ro^2)
409--
410*/
411int NormCo(double *x,double *y
412 ,double mx,double my,double sx,double sy,double ro)
413{
414double a,b,sa;
415if( ro <= -1. || ro >= 1. ) return(1);
416LAB10:
417 b = drand01();
418 if ( b == 0. ) goto LAB10;
419b = sqrt(-2.*log(b));
420a = DeuxPi * drand01();
421sa = sin(a);
422
423*x = mx + sx*b*(sqrt(1.-ro*ro)*cos(a)+ro*sa);
424*y = my + sy*b*sa;
425
426return(0);
427}
428
429
430
431/*==========================================================================*/
432/*
433++
434 Titre Exemple d'utilisation des aleatoires avec initialisation.
435--
436*/
437/*
438++
439| #include "srandgen.h"
440|
441| void main() {
442| long i,ini=123456789;
443| unsigned short seed[3];
444|
445| printf(" 1./ ==> test nitialisation par un long\n");
446| Ini_Ranf_Quick(ini,1);
447| for(i=0;i<10;i++) printf("%d -> %f\n",i,ranf01());
448--
449*/
450/*
451++
452|
453| printf("\n 2./ ==> test initialisation par tableau de 3 unsigned short\n");
454| Ini_Ranf_Quick(ini,1);
455| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
456| Get_Ranf(seed,1);
457| for(i=5;i<10;i++) printf("%d -> %f\n",i,ranf01());
458| Ini_Ranf(seed,1);
459| for(i=5;i<10;i++) printf("%d -> %f\n",i,ranf01());
460| Get_Ranf(seed,1);
461--
462*/
463/*
464++
465|
466| printf("\n 3./ ==> test initialisation automatique\n");
467| Auto_Ini_Ranf(2);
468| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
469| i=0; while(i<10000000) i++;
470| Auto_Ini_Ranf(2);
471| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
472| i=0; while(i<10000000) i++;
473| Auto_Ini_Ranf(2);
474| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
475| }
476--
477*/
478/*
479++
480| 1./ ==> test initialisation par un long
481| Ini_Ranf_Quick: 123456789
482| 0 -> 0.052468
483| 1 -> 0.025444
484| 2 -> 0.099272
485| 3 -> 0.436130
486| 4 -> 0.327740
487| 5 -> 0.821202
488| 6 -> 0.560493
489| 7 -> 0.018157
490| 8 -> 0.872758
491| 9 -> 0.652496
492--
493*/
494/*
495++
496|
497| 2./ ==> test initialisation par tableau de 3 unsigned short
498| Ini_Ranf_Quick: 123456789
499| 0 -> 0.052468
500| 1 -> 0.025444
501| 2 -> 0.099272
502| 3 -> 0.436130
503| 4 -> 0.327740
504--
505*/
506/*
507++
508| Get_Ranf: 36117 51106 21478
509| 5 -> 0.821202
510| 6 -> 0.560493
511| 7 -> 0.018157
512| 8 -> 0.872758
513| 9 -> 0.652496
514--
515*/
516/*
517++
518| Ini_Ranf: 36117 51106 21478
519| 5 -> 0.821202
520| 6 -> 0.560493
521| 7 -> 0.018157
522| 8 -> 0.872758
523| 9 -> 0.652496
524| Get_Ranf: 16576 62373 42761
525--
526*/
527/*
528++
529|
530| 3./ ==> test initialisation automatique
531| Auto_Ini_Ranf: date 887117206 s 868138 10^-6 sec seed=826006868:
532| ... njours=10267 nj23=9 buf=826006868.13800001
533| Ini_Ranf_Quick: 826006868
534| 0 -> 0.798860
535| 1 -> 0.342478
536| 2 -> 0.401300
537| 3 -> 0.442912
538| 4 -> 0.170912
539--
540*/
541/*
542++
543| Auto_Ini_Ranf: date 887117207 s 188779 10^-6 sec seed=826007188:
544| ... njours=10267 nj23=9 buf=826007188.77900004
545| Ini_Ranf_Quick: 826007188
546| 0 -> 0.455599
547| 1 -> 0.811427
548| 2 -> 0.703880
549| 3 -> 0.409569
550| 4 -> 0.390399
551--
552*/
553/*
554++
555| Auto_Ini_Ranf: date 887117207 s 489750 10^-6 sec seed=826007489:
556| ... njours=10267 nj23=9 buf=826007489.75
557| Ini_Ranf_Quick: 826007489
558| 0 -> 0.567094
559| 1 -> 0.893156
560| 2 -> 0.975995
561| 3 -> 0.531331
562| 4 -> 0.834354
563--
564*/
565/*==========================================================================*/
566
567/*==========================================================================*/
568/*
569++
570 Module Tirages aleatoires selon une fonction (C)
571 Lib LibsUtil
572 include srandgen.h
573--
574*/
575/*
576++
577 TIREALEA *init_tirage_alea(int nbin,double xmin,double xmax,double (*fonc) (double))
578 Initialise la structure qui va permettre le tirage aleatoire
579 d'un nombre compris entre xmin et xmax selon la
580 distribution fonc (histo de nbin bins)
581--
582*/
583TIREALEA *init_tirage_alea(int nbin,double xmin,double xmax,double (*fonc) (double))
584{
585int sof,i;
586double x;
587struct tirage_alea *t;
588
589if ( xmax-xmin<0.) return(NULL);
590
591if(nbin<=3) nbin=50;
592
593sof = sizeof(struct tirage_alea);
594if( (t = (struct tirage_alea*)malloc(sof) ) == NULL ) {
595 printf("impossible d'allouer *tirage_alea par malloc \n");
596 return(NULL);
597}
598
599t->Nbin=nbin; t->Min=xmin; t->Max=xmax; t->Lbin=(xmax-xmin) /nbin;
600
601sof = nbin * sizeof(double);
602if( (t->Tab = (double*)malloc(sof) ) == NULL ) {
603 printf("impossible d'allouer *tirage_alea.Tab par malloc \n");
604 return(NULL);
605}
606
607x = xmin + .5*t->Lbin;
608t->Tab[0] = fonc(x);
609for(i=1;i<nbin;i++) {
610 x = xmin + (i+.5)*t->Lbin;
611 t->Tab[i] = t->Tab[i-1] + fonc(x);
612}
613
614for(i=0;i<nbin-1;i++) t->Tab[i] /= t->Tab[nbin-1];
615t->Tab[nbin-1] = 1.;
616
617return(t);
618}
619
620/*==========================================================================*/
621/*
622++
623 double tirage_alea( TIREALEA *alea )
624 tirage aleatoire d'un nombre compris entre xmin et xmax
625 selon la fonction fonc (cf init_tirage_alea).
626--
627*/
628double tirage_alea( TIREALEA *alea )
629{
630int i,ibin = -1;
631double z,t1,t2,x1,x2,t;
632
633z=drand01();
634/* protections z<=0 ou z>=1 */
635if( z <= 0. ) return ( alea->Min );
636if( z >= 1. ) return ( alea->Max );
637/* cas z <= tab[0] */
638if(z <= alea->Tab[0]) {
639 t = alea->Min + (alea->Lbin/2.)/alea->Tab[0] * z;
640 return (t);
641}
642
643/* recherche du premier bin plus grand que z */
644for(i=0;i<alea->Nbin;i++) {
645 ibin=i;
646 if ( z < alea->Tab[i] ) break;
647}
648
649/* extrapolation pour trouver la valeur du tirage aleatoire */
650if( ibin == alea->Nbin-1 ) ibin--;
651t1=alea->Tab[ibin];
652x1 = alea->Min + (ibin+0.5) * alea->Lbin;
653t2=alea->Tab[ibin+1];
654x2 = x1 + alea->Lbin;
655t = x1 + (x2-x1)/(t2-t1) *(z-t1);
656if ( t < alea->Min ) t = alea->Min;
657if ( t > alea->Max ) t = alea->Max;
658return(t);
659}
660
661/*==========================================================================*/
662/*
663++
664 int end_tirage_alea( TIREALEA *alea )
665 De-allocation de la structure qui a permis le tirage aleatoire.
666--
667*/
668int end_tirage_alea( TIREALEA *alea )
669{
670if ( alea != NULL ) { free(alea); return(0);}
671 else return(-1);
672}
Note: See TracBrowser for help on using the repository browser.