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

Last change on this file since 2541 was 1607, checked in by cmv, 24 years ago

after base restructuration cmv 31/7/01

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