source: Sophya/trunk/SophyaLib/NTools/nbrandom.c@ 244

Last change on this file since 244 was 244, checked in by ansari, 26 years ago

beaucoup modifs rz+cmv 22/4/99

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