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

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

NorRand et GauRnd retournent double + elimination des label LAB: , cmv 21/04/2009

File size: 16.1 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*/
189double NorRand(void)
190{
191 double A;
192 while( (A=drand01()) == 0.);
193 return sqrt(-2.*log(A))*cos(DeuxPi*drand01());
194}
195
196/*=========================================================================*/
197/*
198++
199 float NorRand1(void)
200 Generation aleatoire gaussienne normee centree
201 la distribution est limitee entre +/- GAU_RANGE (obsolete).
202--
203*/
204double NorRand1(void)
205{
206double b, x, y, gauss;
207
208b = 1./sqrt(2.*M_PI);
209LAB10:
210x = GAU_RANGE*drandpm1();
211y = drand01()*b;
212gauss = b*exp(-x*x/2.);
213if ( gauss-y < 0. ) goto LAB10 ;
214return x;
215}
216
217/*=========================================================================*/
218/*
219++
220 double GauRnd(double am, double s)
221 Generation aleatoire gaussienne de centre "am" et de sigma "s".
222--
223*/
224/*! \ingroup BaseTools
225 Normal (Gaussian) random number generator with the specified mean
226 (\c am ) and sigma (\c s )
227*/
228double GauRnd(double am, double s)
229{
230double A;
231while( (A=drand01()) == 0. );
232return am + s * sqrt(-2.*log(A))*cos(DeuxPi*drand01());
233}
234
235/*! \ingroup BaseTools
236 \brief Poisson random number generator.
237
238 Return an integer value (>=0) corresponding a Poisson distribution with mean \b mu.
239 \warning NOT the most efficient way of generating a large series of numbers
240 with the SAME mean
241*/
242int PoissRand(double mu)
243{
244 double pp,ppi,x;
245 int n;
246 ppi = pp = exp(-mu);
247 x = drand01();
248 n = 0;
249 while (x > ppi) {
250 n++;
251 pp = mu*pp/(double)n;
252 ppi += pp;
253 }
254 return n;
255}
256
257/*! \ingroup BaseTools
258 \brief Poisson random number generator with approximation for large mean.
259
260 Return an integer value (>=0) corresponding a Poisson distribution with mean \b mu.
261 If \b mu is greater or equal than \b mumax,
262 the large number gaussian approximation is applied.
263 \b mumax=10 is a good value.
264*/
265unsigned long PoissRandLimit(double mu,double mumax)
266// p(n) = (mu^n / n!) exp(-mu) for n = 0, 1, 2, ...
267{
268 double pp,ppi,x;
269 unsigned long n;
270
271 if(mu>=mumax) {
272 pp = sqrt(mu);
273 while( (x=pp*NorRand()) < -mu );
274 return (unsigned long)(mu+x+0.5);
275 }
276
277 ppi = pp = exp(-mu);
278 x = drand01();
279 n = 0;
280 while (x > ppi) {
281 n++;
282 pp = mu*pp/(double)n;
283 ppi += pp;
284 }
285 return n;
286}
287
288/*=========================================================================*/
289/*
290++
291 double GauRnd1(double am, double s)
292 Generation aleatoire gaussienne de centre "am" et de
293 sigma "s" la distribution est limitee entre am +/- GAU_RANGE (obsolete).
294--
295*/
296/*! \ingroup BaseTools
297 \brief OBSOLETE (gaussian random number generator)
298*/
299double GauRnd1(double am, double s)
300{
301double s2, b, x, y, gauss;
302
303s2 = 2.*s*s;
304b = 1./sqrt(2.*M_PI*s);
305LAB10:
306x = am + GAU_RANGE*s*drandpm1();
307y = drand01()*b;
308gauss = b*exp(-(x-am)*(x-am)/s2);
309if ( gauss-y < 0. ) goto LAB10 ;
310return(x);
311}
312
313/*==========================================================================*/
314/*
315++
316 void NormGau(double *x,double *y,double mx,double my,double sa,double sb,double teta);
317 Tirage de 2 nombres aleatoires x et y distribues sur une gaussienne 2D
318 de centre (x=mx,y=my), de sigmas grand axe et petit axe (sa,sb)
319 et dont le grand axe fait un angle teta (radian) avec l'axe des x.
320--
321*/
322/*
323++
324| - La densite de probabilite (normalisee a 1) sur laquelle on tire est:
325| N*exp[-0.5*{ (A/sa)**2+(C/sc)**2 }], N=1/(2Pi*sa*sc)
326| ou A et B sont les coordonnees selon le grand axe et le petit axe
327| et teta = angle(x,A), le resultat subit ensuite une rotation d'angle teta.
328| - La matrice des covariances C des variables A,B est:
329| | sa^2 0 |
330| | | et det(C) = (1-ro^2)*sa^2*sb^2
331| | 0 sb^2 |
332| - La distribution x,y resultante est:
333| N*exp[-0.5*{[(dx/sx)^2-2*ro/(sx*sy)*dx*dy+(dy/sy)^2]/(1-ro^2)}]
334| ou N est donne dans NormCo et sx,sy,ro sont calcules a partir
335| de sa,sc,teta (voir fonctions paramga ou gaparam). La matrice des
336| covariances des variables x,y est donnee dans la fonction NormCo.
337--
338*/
339void NormGau(double *x,double *y
340 ,double mx,double my,double sa,double sb,double teta)
341{
342double c,s,X,Y;
343
344while( (s = drand01()) == 0. );
345s = sqrt(-2.*log(s));
346c = DeuxPi * drand01();
347
348X = sa*s*cos(c);
349Y = sb*s*sin(c);
350
351c = cos(teta); s = sin(teta);
352*x = mx + c*X - s*Y;
353*y = my + s*X + c*Y;
354}
355
356/*==========================================================================*/
357/*
358++
359 int NormCo(double *x,double *y,double mx,double my,double sx,double sy,double ro)
360 Tirage de 2 nombres aleatoires x et y distribues sur une gaussienne 2D
361 de centre (mx,my), de coefficient de correlation rho (ro) et telle que
362 les sigmas finals des variables x et y soient sx,sy (ce sont
363 les valeurs des distributions marginales des variables aleatoires x et y
364 c'est a dire les sigmas des projections x et y de l'histogramme 2D
365 de la gaussienne). Retourne 0 si ok.
366--
367*/
368/*
369++
370| - La densite de probabilite (normalisee a 1) sur laquelle on tire est:
371| N*exp[-0.5*{[(dx/sx)^2-2*ro/(sx*sy)*dx*dy+(dy/sy)^2]/(1-ro^2)}]
372| avec dx = x-mx, dy = y-my et N = 1/[2Pi*sx*sy*sqrt(1-ro^2)]
373| - Dans ce cas la distribution marginale est (ex en X):
374| 1/(sqrt(2Pi)*sx) * exp[-0.5*{dx^2/sx^2}]
375| - La matrice des covariances C des variables x,y est:
376| | sx^2 ro*sx*sy |
377| | | et det(C) = (1-ro^2)*sx^2*sy^2
378| | ro*sx*sy sy^2 |
379| - La matrice inverse C^(-1) est:
380| | 1/sx^2 -ro/(sx*sy) |
381| | | * 1/(1-ro^2)
382| | -ro/(sx*sy) 1/sy^2 |
383--
384*/
385/*
386++
387| - Remarque:
388| le sigma que l'on obtient quand on fait une coupe de la gaussienne 2D
389| en y=0 (ou x=0) est: SX0(y=0) = sx*sqrt(1-ro^2) different de sx
390| SY0(x=0) = sy*sqrt(1-ro^2) different de sy
391| La distribution qui correspond a des sigmas SX0,SY0
392| pour les coupes en y=0,x=0 de la gaussienne 2D serait:
393| N*exp[-0.5*{ (dx/SX0)^2-2*ro/(SX0*SY0)*dx*dy+(dy/SY0)^2 }]
394| avec N = sqrt(1-ro^2)/(2Pi*SX0*SY0) et les variances
395| des variables x,y sont toujours
396| sx=SX0/sqrt(1-ro^2), sy=SY0/sqrt(1-ro^2)
397--
398*/
399int NormCo(double *x,double *y
400 ,double mx,double my,double sx,double sy,double ro)
401{
402double a,b,sa;
403if( ro <= -1. || ro >= 1. ) return(1);
404while( (b=drand01()) == 0. );
405b = sqrt(-2.*log(b));
406a = DeuxPi * drand01();
407sa = sin(a);
408
409*x = mx + sx*b*(sqrt(1.-ro*ro)*cos(a)+ro*sa);
410*y = my + sy*b*sa;
411
412return(0);
413}
414
415
416
417/*==========================================================================*/
418/*
419++
420 Titre Exemple d'utilisation des aleatoires avec initialisation.
421--
422*/
423/*
424++
425| #include "srandgen.h"
426|
427| void main() {
428| long i,ini=123456789;
429| unsigned short seed[3];
430|
431| printf(" 1./ ==> test nitialisation par un long\n");
432| Ini_Ranf_Quick(ini,1);
433| for(i=0;i<10;i++) printf("%d -> %f\n",i,ranf01());
434--
435*/
436/*
437++
438|
439| printf("\n 2./ ==> test initialisation par tableau de 3 unsigned short\n");
440| Ini_Ranf_Quick(ini,1);
441| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
442| Get_Ranf(seed,1);
443| for(i=5;i<10;i++) printf("%d -> %f\n",i,ranf01());
444| Ini_Ranf(seed,1);
445| for(i=5;i<10;i++) printf("%d -> %f\n",i,ranf01());
446| Get_Ranf(seed,1);
447--
448*/
449/*
450++
451|
452| printf("\n 3./ ==> test initialisation automatique\n");
453| Auto_Ini_Ranf(2);
454| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
455| i=0; while(i<10000000) i++;
456| Auto_Ini_Ranf(2);
457| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
458| i=0; while(i<10000000) i++;
459| Auto_Ini_Ranf(2);
460| for(i=0;i<5;i++) printf("%d -> %f\n",i,ranf01());
461| }
462--
463*/
464/*
465++
466| 1./ ==> test initialisation par un long
467| Ini_Ranf_Quick: 123456789
468| 0 -> 0.052468
469| 1 -> 0.025444
470| 2 -> 0.099272
471| 3 -> 0.436130
472| 4 -> 0.327740
473| 5 -> 0.821202
474| 6 -> 0.560493
475| 7 -> 0.018157
476| 8 -> 0.872758
477| 9 -> 0.652496
478--
479*/
480/*
481++
482|
483| 2./ ==> test initialisation par tableau de 3 unsigned short
484| Ini_Ranf_Quick: 123456789
485| 0 -> 0.052468
486| 1 -> 0.025444
487| 2 -> 0.099272
488| 3 -> 0.436130
489| 4 -> 0.327740
490--
491*/
492/*
493++
494| Get_Ranf: 36117 51106 21478
495| 5 -> 0.821202
496| 6 -> 0.560493
497| 7 -> 0.018157
498| 8 -> 0.872758
499| 9 -> 0.652496
500--
501*/
502/*
503++
504| Ini_Ranf: 36117 51106 21478
505| 5 -> 0.821202
506| 6 -> 0.560493
507| 7 -> 0.018157
508| 8 -> 0.872758
509| 9 -> 0.652496
510| Get_Ranf: 16576 62373 42761
511--
512*/
513/*
514++
515|
516| 3./ ==> test initialisation automatique
517| Auto_Ini_Ranf: date 887117206 s 868138 10^-6 sec seed=826006868:
518| ... njours=10267 nj23=9 buf=826006868.13800001
519| Ini_Ranf_Quick: 826006868
520| 0 -> 0.798860
521| 1 -> 0.342478
522| 2 -> 0.401300
523| 3 -> 0.442912
524| 4 -> 0.170912
525--
526*/
527/*
528++
529| Auto_Ini_Ranf: date 887117207 s 188779 10^-6 sec seed=826007188:
530| ... njours=10267 nj23=9 buf=826007188.77900004
531| Ini_Ranf_Quick: 826007188
532| 0 -> 0.455599
533| 1 -> 0.811427
534| 2 -> 0.703880
535| 3 -> 0.409569
536| 4 -> 0.390399
537--
538*/
539/*
540++
541| Auto_Ini_Ranf: date 887117207 s 489750 10^-6 sec seed=826007489:
542| ... njours=10267 nj23=9 buf=826007489.75
543| Ini_Ranf_Quick: 826007489
544| 0 -> 0.567094
545| 1 -> 0.893156
546| 2 -> 0.975995
547| 3 -> 0.531331
548| 4 -> 0.834354
549--
550*/
551/*==========================================================================*/
552
553/*==========================================================================*/
554/*
555++
556 Module Tirages aleatoires selon une fonction (C)
557 Lib LibsUtil
558 include srandgen.h
559--
560*/
561/*
562++
563 TIREALEA *init_tirage_alea(int nbin,double xmin,double xmax,double (*fonc) (double))
564 Initialise la structure qui va permettre le tirage aleatoire
565 d'un nombre compris entre xmin et xmax selon la
566 distribution fonc (histo de nbin bins)
567--
568*/
569TIREALEA *init_tirage_alea(int nbin,double xmin,double xmax,double (*fonc) (double))
570{
571int sof,i;
572double x;
573struct tirage_alea *t;
574
575if ( xmax-xmin<0.) return(NULL);
576
577if(nbin<=3) nbin=50;
578
579sof = sizeof(struct tirage_alea);
580if( (t = (struct tirage_alea*)malloc(sof) ) == NULL ) {
581 printf("impossible d'allouer *tirage_alea par malloc \n");
582 return(NULL);
583}
584
585t->Nbin=nbin; t->Min=xmin; t->Max=xmax; t->Lbin=(xmax-xmin) /nbin;
586
587sof = nbin * sizeof(double);
588if( (t->Tab = (double*)malloc(sof) ) == NULL ) {
589 printf("impossible d'allouer *tirage_alea.Tab par malloc \n");
590 return(NULL);
591}
592
593x = xmin + .5*t->Lbin;
594t->Tab[0] = fonc(x);
595for(i=1;i<nbin;i++) {
596 x = xmin + (i+.5)*t->Lbin;
597 t->Tab[i] = t->Tab[i-1] + fonc(x);
598}
599
600for(i=0;i<nbin-1;i++) t->Tab[i] /= t->Tab[nbin-1];
601t->Tab[nbin-1] = 1.;
602
603return(t);
604}
605
606/*==========================================================================*/
607/*
608++
609 double tirage_alea( TIREALEA *alea )
610 tirage aleatoire d'un nombre compris entre xmin et xmax
611 selon la fonction fonc (cf init_tirage_alea).
612--
613*/
614double tirage_alea( TIREALEA *alea )
615{
616int i,ibin = -1;
617double z,t1,t2,x1,x2,t;
618
619z=drand01();
620/* protections z<=0 ou z>=1 */
621if( z <= 0. ) return ( alea->Min );
622if( z >= 1. ) return ( alea->Max );
623/* cas z <= tab[0] */
624if(z <= alea->Tab[0]) {
625 t = alea->Min + (alea->Lbin/2.)/alea->Tab[0] * z;
626 return (t);
627}
628
629/* recherche du premier bin plus grand que z */
630for(i=0;i<alea->Nbin;i++) {
631 ibin=i;
632 if ( z < alea->Tab[i] ) break;
633}
634
635/* extrapolation pour trouver la valeur du tirage aleatoire */
636if( ibin == alea->Nbin-1 ) ibin--;
637t1=alea->Tab[ibin];
638x1 = alea->Min + (ibin+0.5) * alea->Lbin;
639t2=alea->Tab[ibin+1];
640x2 = x1 + alea->Lbin;
641t = x1 + (x2-x1)/(t2-t1) *(z-t1);
642if ( t < alea->Min ) t = alea->Min;
643if ( t > alea->Max ) t = alea->Max;
644return(t);
645}
646
647/*==========================================================================*/
648/*
649++
650 int end_tirage_alea( TIREALEA *alea )
651 De-allocation de la structure qui a permis le tirage aleatoire.
652--
653*/
654int end_tirage_alea( TIREALEA *alea )
655{
656if ( alea != NULL ) { free(alea); return(0);}
657 else return(-1);
658}
Note: See TracBrowser for help on using the repository browser.