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

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

Creation module DPC/NTools Reza 09/04/99

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