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

Last change on this file since 3099 was 3099, checked in by ansari, 19 years ago

Ajout PoissRand() + classe RandomGenerator / doc ds srandgen.h .cc , Reza 02/11/2006

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