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

Last change on this file since 1274 was 913, checked in by ansari, 25 years ago

Documentation + Modifs mineures (namespace, etc..) - Reza 13/4/2000

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