Esercizio Costruiamo un generatore di numeri random, per esempio

Transcript

Esercizio Costruiamo un generatore di numeri random, per esempio
Esercizio
ƒ Costruiamo un generatore di numeri
random, per esempio secondo una
gaussiana.
ƒ Per generare una generatore di numeri
random distribuiti secondo una gaussiana
usiamo un metodo semplice e
sufficientemente preciso: il metodo BoxMuller. See Numerical Receipies in
Fortran,C o C++ chapter 7.2
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
265
Esercizio
ƒ Di solito in quasi tutti i linguaggi di
programmazione abbiamo a disposizione un
generatore di numeri random secondo una
distribuzione piatta, ovvero con una
distribuzione di probabilità uniforme di generare
un numero tra x e x+dx:
⎧dx 0 < x < 1
p ( x)dx = ⎨
⎩0 per ogni altro valore
ƒ Essendo la probabilità normalizzata:
∞
∫ p( x)dx = 1
−∞
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
266
Esercizio
ƒ Nel caso del C e del C++ abbiamo un
generatore che genera numeri random, fino a
RAND_MAX (macro di preprocessore): rand()
ƒ Quindi, se si desidera una variabile uniforme
nell’intervallo [0,1[, di solito si definisce:
#define DRAND(PAR) rand()/(double)RAND_MAX
ƒ E’ anche possibile definire il seme di partenza
usando: sran( int )
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
267
Esercizio
ƒ Supponiamo di sapere generare in modo
uniforme x, e consideriamo una funzione:
y (x)
la sua distribuzione di probabilità sara:
p ( y )dy
ovvero:
p ( y )dy = p ( x)dx
dx
p( y ) = p( x)
dy
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
268
Esercizio
ƒ Quindi se la probabilità di una distribuzione
arbitraria è una funzione positiva, invertibile
e normalizzata ad 1, avremo:
p( y) = f ( y)
∞
∫
f ( y) = 1
−∞
dx
= f ( y)
dy
ƒ La soluzione dell’ultima
eq. differenziale:
y
y
x = F ( y ) = ∫ f ( y )dy = ∫ p ( y )dy
0
0
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
269
Esercizio
ƒ Quindi la trasformazione che da una
distribuzione uniforme ci porta ad una
distribuita secondo f ( y ) è:
−1
y ( x) = F ( x)
−1
essendo F la funzione inversa di F .
ƒ Tutto dipende dall’invertibilità dell’integrale
di f ( y ) e dalla sua calcolabilità (numerica o
analitica)
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
270
Esercizio
ƒ C’è una semplice interpretazione geometrica.
F ( y ) altri non è che l’area sotto la curva di
probabilità a sinistra di y .
ƒ Quindi devo:
ƒ Scegliere x random
ƒ Trovare il valore y
per cui l’integrale
della curva di probabilità
vale x
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
271
Esercizio
ƒ Nel caso del metodo Box-Muller, partiamo da:
2
y
−
1
p ( y ) dy =
e 2 dy
2π
ƒ E consideriamo l’estensione del metodo
precedente in più dimensioni:
p ( y 1 , y 2 , K ) dy 1 dy 2 K =
∂ (x1 , x 2 , K )
dy 1 dy 2 K
p ( x1 , x 2 , K )
∂ ( y1 , y 2 , K )
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
272
Esercizio
ƒ E consideriamo:
y1 =
− 2 ln x 1 cos( 2 π x 2 )
y2 =
− 2 ln x 1 sin( 2 π x 2 )
ƒ Queste le possiamo invertire:
⎡ 1
x 1 = exp ⎢ − ( y 12 +
⎣ 2
⎛ y2
1
x2 =
arctan ⎜⎜
2π
⎝ y1
⎤
y )⎥
⎦
⎞
⎟⎟
⎠
2
2
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
273
Esercizio
ƒ Lo Jacobiano diventa quindi:
∂ x1
∂ ( x1 , x 2 )
∂ y1
=
∂x2
∂ ( y1 , y 2 )
∂ y1
⎡
−⎢
⎢⎣
1
e
2π
y 12
−
2
⎤⎡
⎥⎢
⎥⎦ ⎢⎣
∂ x1
∂y2
=
∂x2
∂y2
1
e
2π
y 22
−
2
⎤
⎥
⎥⎦
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
274
Esercizio
ƒ Possiamo generare x1 e x 2 indipendentemente
per ottenere le due y 1 e y 2
ƒ Se consideriamo le variabili trigonometriche:
R 2 ≡ v12 + v 22 → x1
angle ( v 1 , v 2 ) → 2 π x 2
ƒ Possiamo scrivere:
(
− 2 ln x (v
y1 =
− 2 ln x 1 v 1 /
y2 =
/
1
2
)
R )
R2
2
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
275
Esercizio
ƒ In breve:
ƒ Generiamo v 1 e v 2 nel quadrato di lati [-1,1]
ƒ Controlliamo che siano nella circonferenza unitaria
ƒ Calcoliamo y 1 e y 2 con la trasformazione di BoxMuller:
(
− 2 ln x (v
y1 =
− 2 ln x 1 v 1 /
y2 =
/
1
2
)
R )
R2
2
ƒ Ritorniamo un valore e salviamo l’altro per il
passaggio successivo.
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
276
Esercizio
ƒ
double v1,v2,rsq,fac,g;
switch(_flag){
case 0:
// Generate two new random number
rsq=2.;
while( (rsq>=1.) || (rsq==0.) ){
v1=2.*DRAND()-1.;
v2=2.*DRAND()-1.;
rsq=pow(v1,2.)+pow(v2,2.);
}
fac=sqrt(-2.*log(rsq)/rsq);
_g1=v1*fac;
_g2=v2*fac;
_flag=1;
g=_g1;
break;
case 1:
g=_g2;
_flag=0;
break;
default:
std::cout << " gaussrnd::Grnd flag error ! _flag= "
<< _flag << std::endl;
break;
}
return g;
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
277
Esercizio
ƒ
#ifndef GAUSSRND_H
#define GAUSSRND_H
#include <iostream>
#include <cstdlib>
#include <cmath>
#define DRAND(PAR) rand()/(double)RAND_MAX
#define SRAND(PAR) srand(PAR)
#define RANGEN
// To generate a normal distributed Gaussian rand number
// distribution using the Box-Muller method. See Numerical Receipies
// in Fortran, chapter 7.2
class gaussrnd{
private:
int _flag;
int _seed;
double _g1,_g2;
public:
// Init the rand48 random number generator
gaussrnd(const int &seed=0 ): _flag(0) {NewSeq(seed);}
// Inizialize a new random sequence
void NewSeq(const int &seed) {_seed=seed; SRAND(_seed);}
double Grnd();
void Print();
};
#endif //GAUSSRND_H
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
278
Esercizio
ƒ
#include "gaussrnd.h"
double gaussrnd::Grnd(){
double v1,v2,rsq,fac,g;
switch(_flag){
}
case 0:
// Generate two new random number
rsq=2.;
while( (rsq>=1.) || (rsq==0.) ){
v1=2.*DRAND()-1.;
v2=2.*DRAND()-1.;
rsq=pow(v1,2.)+pow(v2,2.);
}
fac=sqrt(-2.*log(rsq)/rsq);
_g1=v1*fac;
_g2=v2*fac;
_flag=1;
g=_g1;
break;
case 1:
g=_g2;
_flag=0;
break;
default:
std::cout << " gaussrnd::Grnd flag error ! _flag= "
<< _flag << std::endl;
break;
}
return g;
void gaussrnd::Print() {
std::cout << " gaussrnd::Print max random number: " << RAND_MAX << std::endl
<< "
Seed : " << _seed << std::endl;
}
F.S. Cafagna, Linguaggi di programmazione avanzati:
C++ , XXIII ciclo
279
Esercizio
ƒ
ƒ Adesso che abbiamo il nostro generatore
random, come facciamo a controllarne il
risultato, i.e. a vedere la distribuzione ?
ƒ Costruiamo un istogramma !!
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
280
Esercizio
ƒ
ƒ Immaginiamo una semplice classe
con un massimo, un minimo ed un numero di divisioni:
struct simple{
double xmin_,xmax_;
int bin_;
};
e pensiamo ad un metodo:
int simple::Bin( double x ) {
return (x>=max_) ? (bin_+1): int( ((x-min_)/((max_-min_)/bin_));
}
ƒ Questo metodo, dato un valore x, ritorna:
ƒ bin_+1, se x è maggiore o uguale di max_
ƒ un intero tra 1 e bin_, se x è maggiore di min_ e minore di
max_
ƒ Un numero minore uguale a 0 se x è minore o uguale a min_
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
281
Esercizio
ƒ
ƒ Immaginiamo una semplice classe
con un massimo, un minimo ed un numero di divisioni:
struct simple{
double xmin_,xmax_;
int bin_;
};
e pensiamo ad un metodo:
int simple::Bin( double x ) {
return (x>=max_) ? (bin_+1): int( ((x-min_)/((max_-min_)/bin_));
}
ƒ Questo metodo, dato un valore x, ritorna:
ƒ bin_+1, se x è maggiore o uguale di max_
ƒ un intero tra 1 e bin_, se x è maggiore di min_ e minore di
max_
ƒ Un numero minore uguale a 0 se x è minore o uguale a min_
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
282
Esercizio
ƒ
ƒ Quindi se scrivo:
int Max(const int a, const int b) const {
return ( a<b) ? b: a; }
Posso riscrivere Bin:
int simple::Bin( double x ) {
return Max(
(x>=max_) ? (bin_+1): int( ((x-min_)/((max_-min_)/bin_)), 0 );
}
ƒ Adesso Bin(x), dato un valore x, ritorna:
ƒ bin_+1, se x è maggiore o uguale di max_
ƒ un intero tra 1 e bin_, se x è maggiore di min_ e minore di
max_
ƒ Un numero uguale a 0 se x è minore o uguale a min_
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
283
Esercizio
ƒ
ƒ Quindi questo oggetto dato un range: ]min_, max_[, ed un
numero di bin: bin_, ritorna il numero di bin di un valore
qualsiasi: x
ƒ Se gli aggiungo un titolo, posso utilizzarlo come asse
dell’istogramma:
class axis {
public:
int Bin(double x) ;
private:
int Max(const int a, const int b) const ;
double max_;
double min_;
int bin_;
string title_;
};
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
284
Esercizio
ƒ
ƒ Completandola con setters, getters e Print():
class axis {
public:
int Bin(double x) ;
double GetMax() const { return
max_; }
double GetMin() const { return
min_; }
int GetBin() const { return bin_; }
const char * GetTitle() const {
return title_.c_str(); }
void SetMax( double x ) { max_ =
x; }
void SetMin( double x ) { min_ = x;
}
void SetBin( int x ) { bin_ = x; }
void SetTitle( const char *x ) {
title_=x; }
void SetTitle( const string & x ) {
SetTitle(x.c_str() ) ; }
void Print() const;
private:
int Max(const int a, const int b)
const ;
double max_;
double min_;
int bin_;
string title_;
};
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
285
Esercizio
ƒ
ƒ Potrebbe tornare comodo il metodo inverso di Bin():
#define BINERROR -999999.
#define UNDERFLOW -1111111.
#define OVERFLOW 111111.
double axis::GetBinMin( const int i ) const {
if(!i) return UNDERFLOW;
if(i==bin_+1) return OVERFLOW;
return (i<=bin_) ? double(min_+(i-1)*(((max_min_)/bin_))) : BINERROR;
}
ƒ Questo metodo dato un intero i ritorna:
ƒ-1111111., se i è pari a 0, UNDERFLOW;
ƒ 1111111., se i è pari a bin_+1, OVERFLOW;
ƒ-999999., se i è maggiore di bin_+1, BINERROR;
ƒ un valore compreso tra min_ e max_ se i e compreso tra 1 e bin_
ƒ Quindi calcolare l’estremo superiore:
double GetBinMax( const int i ) const { return GetBinMin(i+1);
}
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
286
Esercizio
ƒ
ƒ Quindi la class definition finale diventa:
#ifndef AXIS_H
#define AXIS_H
#include <iostream>
#define BINERROR -999999.
#define UNDERFLOW -1111111.
#define OVERFLOW 111111.
using std::string;
using std::cout;
using std::endl;
class axis {
public:
int Bin(double x) ;
double GetMax() const { return max_; }
double GetMin() const { return min_; }
int GetBin() const { return bin_; }
deouble GetBinMin) const int I ) const;
double GetBinMax( const int i ) const
{ return GetBinMin(i+1); }
const char * GetTitle() const { return
title_.c_str(); }
const char * GetTitle() const { return
title_.c_str(); }
void SetMax( double x ) { max_ = x; }
void SetMin( double x ) { min_ = x; }
void SetBin( int x ) { bin_ = x; }
void SetTitle( const char *x ) { title_=x; }
void SetTitle( const string & x ) {
SetTitle(x.c_str() ) ; }
void Print() const;
private:
int Max(const int a, const int b)
const ;
double max_;
double min_;
int bin_;
string title_;
axis.h
};
# endif //AXIS_H
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
287
Esercizi
ƒ Quindi un istogramma
potrebbe essere fatto :
typedef vector <int> vint;
class hist {
Crea un vector di interi
public:
hist(double xmax=1., double xmin=0., int bin=100,
const char *t="none", const char *at="none"):
xaxis_(xmax,xmin,bin,at), count_(bin+2), entries_(0), title_(t) {};
bool Fill(double x){ int i=xaxis_.Bin(x);
if(i<=count_.size()) {
count_[i]++;
entries_++;
return true;
}
return false;
}
Sfrutta Bin(int) di axis per
calcolare il numero di bin che
sarà l’i-esimo oggetto contenuto
nel vector
private:
vint count_;
axis xaxis_;
int entries_;
string title_;
};
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
288
Esercizi
ƒ Notare l’utilizzo del costruttore di
vector in cui viene specificato il
numero di elementi iniziali da creare:
hist(double xmax=1., double xmin=0., int bin=100,
const char *t="none", const char *at="none"):
xaxis_(xmax,xmin,bin,at), count_(bin+2), entries_(0),
title_(t) {};
ƒ count_(bin+2) è equivalente a:
ƒ vector <int, (bin+2) > // crea un vector che contiene
inizialmente (bin+2) oggetti di tipo int
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
289
Esercizio
ƒ
ƒ Al solito con getters e setters avremo:
// Getters
int GetEntries() const { return entries_; }
int GetNbin() const { return xaxis_.GetBin(); }
double GetXmax() const { return xaxis_.GetMax(); }
double GetXmin() const { return xaxis_.GetMin(); }
const char * GetTitle() const { return title_.c_str(); }
const char * GetATitle() const { return xaxis_.GetTitle(); }
#ifndef HIST_H
#ifndef HIST_H
#define HIST_H
#include <vector>
#include <string>
#include "axis.h"
using std::vector;
using std::string;
typedef vector <int> vint;
class hist {
public:
hist(double xmax=1., double xmin=0., int bin=100,
const char *t="none", const char *at="none"):
xaxis_(xmax,xmin,bin,at), count_(bin+2), entries_(0),
title_(t) {};
bool Fill(double x){ int i=xaxis_.Bin(x);
if(i<=count_.size()) {
count_[i]++;
entries_++;
return true;
}
return false;
}
// Setters
void SetNbin( const int i ) { xaxis_.SetBin(i); }
void SetXmax( const double i ) { xaxis_.SetMax(i); }
void SetXmin( const double i ) { xaxis_.SetMin(i); }
void SetTitle( const char *c ) { title_=c; }
void SetATitle( const char *c) { xaxis_.SetTitle(c); }
private:
vint count_;
axis xaxis_;
int entries_;
string title_;
};
#endif // HIST_H
hist.h
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
290
Esercizio
ƒ Rimane il problema di stampare il contenuto:
void Print( ostream &o = cout) const {
o << " Histo : " << title_ << endl;
o << " Underflow : " << *count_.begin()
<< ", Overflow : " << *count_.end() << endl;
for( int i=0; i<(count_.size()); PrintBin(i++,o) );
}
void PrintBin( const int I, ostream &o) const {
o << " Bin : " << i << ", " << xaxis_.GetBinMin(i)
<< ", " << count_[i] << endl;
}
ƒ Notare la generalizzazione dell’output stream. In questo
modo sarà possibile usare un file-stream invece di cout
e salvare l’output su file
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
291
Esercizio
ƒ In questo modo viene stampato il contenuto di
ogni bin, ma possiamo pensare ad un modo per
ottenere un “grafico” ?
ƒ Se abbiamo a disposizione MAXCHAR colonne
su un terminale ASCII, potremmo pensare di
scrivere una stringa lunga L dove:
ƒ MAXCHAR:L=max_bin_content:bin_content
ƒ Quindi una volta calcolato il massimo contenuto
nei bin, potremo calcolare il fattore di scala:
ƒ MAXCHAR/max_bin_content
ƒ E calcolare:
ƒ L=bin_content*(MAXCHAR/max_bin_content)
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
292
Esercizio
ƒ Per calcolare il massimo conteggio nel bin,
possiamo usare un algoritmo della STL:
max_element
ƒ E’ dichiarato nell’header: algorithm
ƒ E la sua dichiarazione recita:
template <class ForwardIterator> ForwardIterator max_element (
ForwardIterator first, ForwardIterator last );
template <class ForwardIterator, class Compare> ForwardIterator
max_element ( ForwardIterator first, ForwardIterator last, Compare
comp );
ƒ Quindi dati due iteratori, controlla il valore di
tutti gli oggetti a cui gli iteratori puntano e
ritorna l’iteratore che punta all’oggetto con il
contenuto maggiore secondo la classe di
comparazione comp
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
293
Esercizio
ƒ Per cui, nella nostra classe hist potremmo
scrivere:
int maxele=*(max_element(
count_.begin()+1, count_.end()-1));
ƒ Una volta calcolato il massimo contenuto nel bin,
possiamo calcolare Il fattore di scala e stampare
una linea che contiene un numero di caratteri
proporzionale al contenuto del bin.
ƒ Per questo sfruttiamo le proprietà delle
stringstream ed il creatore non di default delle
string
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
294
Esercizio
void Print( ostream & o=cout,) const {
int maxele=*(max_element( count_.begin()+1, count_.end()-1));
o << " Histo : " << title_ << endl;
o << " Max value : " << maxele << endl;
Calcolo
o << " Underflow : " << *count_.begin()
<< ", Overflow : " << *count_.end() << endl;
for( int i=0; i<(count_.size()); PrintBin(i++,o) );
for( int i=1; i<(count_.size()-1); PrintBin(i++, o, MAXCHAR/maxele ) );
}
il massimo
// scale, must be equal to MAXCHAR / MAXELE
void PrintBin( const int i, ostream &o=cout, double scale=0 ) const {
if(!scale) {
o << " Bin : " << i << ", " << xaxis_.GetBinMin(i)
<< ", " << count_[i] << endl;
Calcolo L
} else {
int j=(int)(count_[i]*scale);
Scrivo nella stringa come se
stringstream s;
s<< setw(6) << xaxis_.GetBinMin(i)<<"|";
fosse uno stream il valore del
s<< left << string(j,'-') << "|";
bin
o << s.str() << endl;
}
}
Creo una string di L caratteri ‘-’
e la scrivo nella stringstream
Modificatori di I/O.
setw(int):fissa la largezza di campo
295
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
left: allinea a sinistra
Esercizio
ƒ Aggiungendo delle opzioni per selezionare il PLOT o il print del
BIN content, la class definition diventa:
#ifndef HIST_H
#define HIST_H
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include "axis.h"
// Getters
int GetEntries() const { return entries_; }
int GetNbin() const { return xaxis_.GetBin(); }
double GetXmax() const { return xaxis_.GetMax(); }
double GetXmin() const { return xaxis_.GetMin(); }
const char * GetTitle() const { return title_.c_str(); }
const char * GetATitle() const { return xaxis_.GetTitle(); }
// Setters
void SetNbin( const int i ) { xaxis_.SetBin(i); }
void SetXmax( const double i ) { xaxis_.SetMax(i); }
void SetXmin( const double i ) { xaxis_.SetMin(i); }
void SetTitle( const char *c ) { title_=c; }
void SetATitle( const char *c) { xaxis_.SetTitle(c); }
using std::vector;
using std::string;
using std::stringstream;
using std::right;
using std::fixed;
using std::endl;
using std::cout;
using std::left;
using std::setw;
using std::ostream;
void Print( ostream & o=cout, opt op=PLOT ) const;
// scale, must be equal to MAXCHAR / MAXELE
void PrintBin( const int i, ostream &o=cout, double scale=0. ) const;
#define MAXCHAR 60.
typedef vector <int> vint;
class hist {
public:
enum opt {ALL,BIN,PLOT};
hist(double xmax=1., double xmin=0., int bin=100,
const char *t="none", const char *at="none"):
xaxis_(xmax,xmin,bin,at), count_(bin+2), entries_(0), title_(t) {};
private:
vint count_;
axis xaxis_;
int entries_;
string title_;
};
#endif // HIST_H
hist.h
bool Fill(double x);
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
296
Esercizio
#include "hist.h"
void hist::Print( ostream & o, opt op) const {
int maxele=*(max_element( count_.begin()+1,
count_.end()-1));
o << " Histo : " << title_ << endl;
o << " Max value : " << maxele << endl;
o << " Underflow : " << *count_.begin()
<< ", Overflow : " << *count_.end() << endl;
switch(op) {
case BIN:
for( int i=0; i<(count_.size()); PrintBin(i++,o) );
break;
case PLOT:
for( int i=1; i<(count_.size()-1); PrintBin(i++, o,
MAXCHAR/maxele ) );
break;
case ALL:
for( int i=0; i<(count_.size()); PrintBin(i++,o) );
for( int i=1; i<(count_.size()-1); PrintBin(i++, o,
MAXCHAR/maxele ) );
break;
}
}
// scale, must be equal to MAXCHAR / MAXELE
void hist::PrintBin( const int i, ostream &o, double scale )
const {
if(!scale) {
o << " Bin : " << i << ", " << xaxis_.GetBinMin(i)
<< ", " << count_[i] << endl;
} else {
int j=(int)(count_[i]*scale);
stringstream s;
s<< setw(6) << xaxis_.GetBinMin(i)<<"|";
s<< left << string(j,'-') << "|";
o << s.str() << endl;
}
}
bool hist::Fill(double x){ int i=xaxis_.Bin(x);
if(i<=count_.size()) {
count_[i]++;
entries_++;
return true;
}
return false;
}
hist.cpp
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
297
Esercizio
ƒ A questo punto non ci resta che usare queste classi
#include "hist.h"
#include "gaussrnd.h"
#include <fstream>
using std::ofstream;
int main() {
hist t(3.,-3., 150, "grandom", "count") ;
gaussrnd g(12345);
for(int j=0; j<500000; j++, t.Fill(g.Grnd()));
ofstream f("test_gauss.dat");
t.Print();
t.Print(f);
return 0;
}
test_hist.cpp
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
298
Esercizio
ƒ Non dimentichiamo il Makefile:
CC=g++
test_hist: hist.o axis.o test_hist.o gaussrnd.o
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
299
Esercizi
ƒ Provate a:
ƒ Correggere la classe axis. Che succede se calcolo
Bin(min_) ? Viene ritornato il numero di bin corretto ?
ƒ Provare ad “estendere” l’utilizzo delle classi axis e
hist, anche ai double utilizzando il template
ƒ Provare a scrivere un generatore di numeri random
distribuiti secondo una esponenziale
−y
(hint: y ( x) =− ln( x), p( y )dy = e dy )
ƒ Provate a scrivere una classe base rndgen, da cui
fare derivare le classi: gaussrnd, exprnd
ƒ Provate a riscrivere il main in modo che utilizzi solo la
classe base dei generatori random e che possiate
scegliere il generatore via cin
F.S. Cafagna, Linguaggi di programmazione avanzati: C++ , XXIII ciclo
300