Programmazione Avanzata per il Calcolo Scientifico Lezione N. 1

Programmazione Avanzata per il Calcolo
Scientifico
Lezione N. 1
Luca Formaggia
MOX
Dipartimento di Matematica “F. Brioschi”
Politecnico di Milano
A.A. 2011/2012
1/1
Aule e orari
Il corso consiste di lezioni ex cathedra che si tengono il
MERCOLEDI dalle 13.15 alle 15.15 e il GIOVEDI dalle 15.15 alle
18.15 e di laboratori didattici che si tengono il VENERDI dalle
15.15 alle 18.15 nel Laboratorio Didattico del Dipartimento (quarto
piano).
2/1
Docenti
I
Docente: Luca Formaggia ([email protected])
I
Esercitatori: Alessio Fumagalli
([email protected]) e Carlo deFalco
([email protected])
Orario di ricevimento: Mercoledi 11.15 13.15 (previo
appuntamento) Libri di testo: C++ and Object Oriented Numeric
Computing for Scientists and Engineers, Daoqi Yang,
Springer-Verlag, 2000
Parallel scientific computing in C++ and MPI, Karniadakis, G. and
Kirby, R.M.,Cambridge University Press, 2003
Note del corso (work in progress)
3/1
Altre risorse on-line
I
Il sito del corso www2.mate.polimi.it:8080//CN/PACS
contiene molto materiale addizionale costantemente
aggiornato.
I
www.cplusplus.com fornisce una eccellente on-line reference
con esempi.
I
www.cppreference.com/wiki è una pagina wiki molto
completa aggiornata all’ultimo standard C++11.
4/1
Modalità di esame
Corso da 8 crediti
I
Valutazione della attività di laboratorio (3 punti)
I
Test in laboratorio didattico
Corso da 10 crediti
I
Valutazione della attività di laboratorio (3 punti)
I
Progetto concordato con il docente (2 crediti)
5/1
Supporto informatico
I portali del corso sono
http://corsi.metid.polimi.it
e
www2.mate.polimi.it:8080/CN/PACS
L’iscrizione al portale METID è necessaria per accedere ai tutti i
servizi.
Il sistema operativo di riferimento è Linux, i compilatori di
riferimento sono i compilatori gnu versione 4.x. Utilizzeremo il
softare eclipse come strumento di sviluppo (IDE) (scaricabile dal
sito www.eclipse.org) Un altra IDE utilizzabile è Code::Blocks
(www.codeblock.org).
Sul portale PACS si trovano informazioni su Linux e su Windows.
6/1
Una nota linguistica
Il corso viene dato in lingua Italiana. Ciononostante, spesso la
terminologia in lingua Inglese è di uso comune (e talvolta più
precisa).
Si farà quindi spesso uso di quest’ultima (cercando comunque di
fornire anche il corrispondente termine in Italiano).
I libri di testo (comprese le note del corso) sono in Inglese.
7/1
8/1
Una possibile definizione
Il calcolo scientifico è la disciplina che permette di riprodurre
efficacemente su un calcolatore un fenomeno o processo descritto
da un opportuno modello matematico, cercando di massimizzare
l’efficienza su una particolare architettura e ridurre gli errori
introdotti dal calcolo (errori di arrotondamento).
9/1
Dalla realtà al computer
Fenomeno Fisico
Osservazione Sperimentale
Modello Concettuale
Modello Matematico
Leggi di Conservazione
Equazioni Differenziali
Modelli Statistici
Programmazione
00
11
00
11
000
111
Linguaggio di programmazione
Implementazione dell’algoritmo
Strutture dati
Ottimizzazione
Analisi
Buona posizione
Proprietà della soluzione
Soluzione analitica
Analisi Numerica
Metodi di discretizzazione
Stima dell’errore
Analisi degli algoritmi
PostProcessing
Visualizzazione
Analisi dei risultati
CALCOLO SCIENTIFICO
10/1
Dall’algoritmo al risultato
CODIFICA
Algoritmo
Risultati
POST
PROCESSING
COMPILAZIONE
Programma
Sorgente
Codice
Macchina
11/1
Implementazione di un linguaggio
I
Interpretato Le istruzioni (comandi) vengono processate
’sequenzialmente’ e ’tradotte’in codice macchina. Esempio:
BASIC, MATLAB, Python.Semplicità di programmazione e
debugging
I
Compilato L’intero codice sorgente viene tradotto in codice
macchina, creando un eseguibile. Esempi: C++, FORTRAN.
Prestazioni migliori. Più difficile il debugging.
I
Semicompilato Il codice sorgente o parte di esso viene tradotto
in un codice intermedio (byte-code) indipendende dalla
architettura. Quest’ultimo viene poi interpretato “run-time” da
una “macchina virtuale” (virtual machine). Esempio: Java.
12/1
Implementazione di un linguaggio
I
Interpretato Le istruzioni (comandi) vengono processate
’sequenzialmente’ e ’tradotte’in codice macchina. Esempio:
BASIC, MATLAB, Python.Semplicità di programmazione e
debugging
I
Compilato L’intero codice sorgente viene tradotto in codice
macchina, creando un eseguibile. Esempi: C++, FORTRAN.
Prestazioni migliori. Più difficile il debugging.
I
Semicompilato Il codice sorgente o parte di esso viene tradotto
in un codice intermedio (byte-code) indipendende dalla
architettura. Quest’ultimo viene poi interpretato “run-time” da
una “macchina virtuale” (virtual machine). Esempio: Java.
12/1
Implementazione di un linguaggio
I
Interpretato Le istruzioni (comandi) vengono processate
’sequenzialmente’ e ’tradotte’in codice macchina. Esempio:
BASIC, MATLAB, Python.Semplicità di programmazione e
debugging
I
Compilato L’intero codice sorgente viene tradotto in codice
macchina, creando un eseguibile. Esempi: C++, FORTRAN.
Prestazioni migliori. Più difficile il debugging.
I
Semicompilato Il codice sorgente o parte di esso viene tradotto
in un codice intermedio (byte-code) indipendende dalla
architettura. Quest’ultimo viene poi interpretato “run-time” da
una “macchina virtuale” (virtual machine). Esempio: Java.
12/1
Il processo di compilazione in C(++) - semplificato -
Compilazione
prog.cc
g++ −c prog.cc
Linking
prog.o
g++ −o prog prog.o
−lblas −lX
Preprocessing
header (#include) files
prog.hpp
other headers
Esecuzione
prog
prog
check
librerie statiche
libblas.a
Loader
librerie dinam.
libX.so
system libraries
Il comando g++ -o prog prog.cc esegue i passi di compilazione e
linking in sequenza.
13/1
Il processo di compilazione in C(++) - semplificato -
Compilazione
prog.cc
g++ −c prog.cc
Linking
prog.o
g++ −o prog prog.o
−lblas −lX
Preprocessing
header (#include) files
prog.hpp
other headers
Esecuzione
prog
prog
check
librerie statiche
libblas.a
Loader
librerie dinam.
libX.so
system libraries
Il comando g++ -o prog prog.cc esegue i passi di compilazione e
linking in sequenza.
13/1
Tipi di programmazione
Programmazione Procedurale.
I dati vengono elaborati da procedure (comandi o funzioni) che ne
modificano lo stato operando (tipicamente) in modo sequenziale.
Programmazione ad oggetti.
I dati sono encapsulati in strutture apposite (classi). Si opera sui
dati tramite metodi della classe. L’accesso diretto ai dati è
normalmente proibito.
Programmazione generica.
Si opera su tipi di dati differenti (ma che soddisfano pre-requisiti
opportuni) usando la stessa interfaccia.
14/1
Tipi di programmazione
Programmazione Procedurale.
I dati vengono elaborati da procedure (comandi o funzioni) che ne
modificano lo stato operando (tipicamente) in modo sequenziale.
Programmazione ad oggetti.
I dati sono encapsulati in strutture apposite (classi). Si opera sui
dati tramite metodi della classe. L’accesso diretto ai dati è
normalmente proibito.
Programmazione generica.
Si opera su tipi di dati differenti (ma che soddisfano pre-requisiti
opportuni) usando la stessa interfaccia.
14/1
Tipi di programmazione
Programmazione Procedurale.
I dati vengono elaborati da procedure (comandi o funzioni) che ne
modificano lo stato operando (tipicamente) in modo sequenziale.
Programmazione ad oggetti.
I dati sono encapsulati in strutture apposite (classi). Si opera sui
dati tramite metodi della classe. L’accesso diretto ai dati è
normalmente proibito.
Programmazione generica.
Si opera su tipi di dati differenti (ma che soddisfano pre-requisiti
opportuni) usando la stessa interfaccia.
14/1
Programmazione procedurale
Esempio in MATLAB
A=gallery(’poisson’,100); b=ones(100,1);
[L,U]=lu(A) y=L\b;
x=U\y;
15/1
Programmazione ad oggetti
Esempio in C++
class Matrix{public:
Matrix(string filename);
Vector solve(Vector const & b);
private:
double * dati;}
...
Matrix A(“file.dat”);Vector b;
Vector x;
x=A.solve(b);
..
Non si può accedere direttamente a dati.
16/1
Programmazione ad oggetti
Esempio in C++
class Matrix{public:
Matrix(string filename);
Vector solve(Vector const & b);
private:
double * dati;}
...
Matrix A(“file.dat”);Vector b;
Vector x;
x=A.solve(b);
..
Non si può accedere direttamente a dati.
16/1
Programmazione generica
Esempio in C++
template<class T> T sqrt(T& x);
...
int main(){
float x; int y; complex z;
flot rx; int ry, complex rz;
rx=sqrt(x); // usa sqrt<float>
ry=sqrt(y); // usa sqrt<int>
rz=sqrt(z); // usa sqrt<complex>
...}
La funzione sqrt<T>(T &) si applica a ogni tipo T purchè esso
soddisfi opportuni prerequisiti stabiliti dal programmatrore (p. es.
x > 0 per dati float e int).
17/1
Programmazione generica
Esempio in C++
template<class T> T sqrt(T& x);
...
int main(){
float x; int y; complex z;
flot rx; int ry, complex rz;
rx=sqrt(x); // usa sqrt<float>
ry=sqrt(y); // usa sqrt<int>
rz=sqrt(z); // usa sqrt<complex>
...}
La funzione sqrt<T>(T &) si applica a ogni tipo T purchè esso
soddisfi opportuni prerequisiti stabiliti dal programmatrore (p. es.
x > 0 per dati float e int).
17/1
Programmazione generica
Un secondo Esempio
template<class T> class Vector {...}
class triangle {...}
int main(){
Vector<float> a;// Un vettore di float
Vector<triangle> b;// Un vettore di triangle ...
triangle t=b[2]; ...}
18/1
Il linguaggio C++
I
Supporta solo la modalità di compilazione (linguaggio
compilato)
I
È una estensione del linguaggio C, quindi supporta la
programmazione procedurale
I
Supporta inoltre la programmazione ad oggetti e la
programmazione generica.
I
Compilatori facilmente disponibili (e spesso gratuiti).
I
È il 3o linguaggio più utilizzato nel mondo (statistiche
Settembre 2010).
I
È un linguaggio complesso e l’utilizzo nel calcolo scientifico
richiede attenzione per evitare degradazione d’efficienza.
I
È costantemente aggiornato: è appena uscito il nuovo
standard (C++11).
19/1
Utilizzo del C++ ()
Popolarita‘ dei linguaggi di programmazione
langpop.com 2010
Java
C
C++
PHP
Javascript
Python
C#
Perl
Pascal
Fortran
20/1
Alternative per il calcolo scientifico
I
I
I
I
I
FortranXX. Programmazione procedurale. Fortran90 ha
introdotto i moduli e la allocazione dinamica della memoria.
Permette di implementare una programmazione “quasi” ad
oggetti. Estremamente efficiente per le operazioni
matematiche.
Java. Lo sviluppo di applicazioni numeriche in Java è limitato
principalmente a scopi didattici o divulgativi (web computing).
C. La maggior parte dei codici commerciali di calcolo
scientifico è scritta in questo linguaggio.
python Utilissimo per interfacce. PyNum è un ambiante che
rende disponibile numerose funzionalità di calcolo scientifico. Il
suo uso nel calcolo scientifico è in forte crescita per la sua
flessibilità.
Matlab Supporta programmazione ad oggetti e può essere
compilato. Il suoi cloni “free software” Octave e Scilab sono
oramai valide alternative.
21/1
la struttura del linguaggio
User
Libraries
Core Language
o
<i
str
e
<vector>
h>
am
>
umfpack.h
libumfpack.a
libblas.so
at
External
Libraries
STANDARD LIBRARY
m
<c
fem.h
libfem.a
tr
<s
ing
>
Il linguaggio è estensibile: al nucleo rappresentato dalle istruzioni
condamentali (if, while,...) si aggiungono i moduli della
standard libray e quelli eventualmenti forniti dall’utente o da altre
librerie
22/1
la struttura del linguaggio
User
Libraries
Core Language
<i
os
tre
<vector>
h>
am
>
umfpack.h
libumfpack.a
libblas.so
at
External
Libraries
STANDARD LIBRARY
m
<c
fem.h
libfem.a
<s
g>
trin
Nel codice l’estensione è riconoscibile dalla presenza della direttiva
#include header_file.
La lista completa degli header files delle standard library si trova a
pag. 125 del libro di testo (un estratto e‘ reperibile sul sito).
22/1
C e C++ header files
Gli header files di sistema dei C++ introducono nomi e funzioni
nello spazio di nomi (namespace) std. Quindi per richiamarli
occorre o usare il full qualified name (nome qualificato) std::xxx o
usare il comando using:
#i n c l u d e <cmath> // i n t r o d u c e s q r t
...
double a=s t d : : s q r t ( 5 . 0 ) ; // f u l l q u a l i f i e d name
...
using std : : s q r t ;
...
double c=s q r t ( 2 ∗ a ) ; // non s e r v e s t d : :
23/1
esempio_ch1
#include <iostream> // include il modulo per l’i/o
// della libreria standard
int main() {
using namespace std; \\rende visibili i nomi della STL
int n, m; // n e m sono 2 interi
cout « ’’Dammi due interi:’’ « endl;
cin » n » m;
if (n > m) {
int temp = n; n = m;
m = temp; }
double sum = 0.0;
for (int i = n; i <= m; i++)
sum += i;// sum += i significa sum = sum + i;
cout « ’’Somma=’’ « sum « endl;
}
24/1
la direttiva “include”
#include<iostream>
using namespace std;
Il linguaggio C++ consiste in un insieme di istruzioni di base (core
language) e “estensioni” le cui definizioni possono essere richiamate
con in comando #include<XXX> dove XXX è un header file.
In particolare la libreria standard (Standard template library o STL)
mette a disposizione il modulo iostream per l’i/o, che definisce
(tra l’altro) std::cin e std::cout per l’i/o da tastiera/terminale.
using namespace std; permette di omettere il qualificatore
(scope qualifier) std:: ai nomi di introdotti dal “modulo” iostream.
25/1
Il programma principale
int main() {
....
for (int i = n; i <= m; i++) a[i]=i;
}
Per produrre un eseguibile il sorgente del programma deve contenere
uno e un solo main() (programma principale o main program).
In C++ il main ritorna sempre un intero (int) e può prendere in
ingresso due argomenti (si veda l’esercitazione) oppure nessuno,
come in questo caso.
Le istruzioni (statement) terminano sempre con il punto e virgola
(;) che funge da separatore. Non vi è un formato predefinito, a
differenza di Python o del Fortran77.
26/1
Le variabili
int n, m;
float x, y;
Triangle t; ...
for (int i = n; i <= m; i++)
I tipi si dividono in due gruppi: i tipi nativi del linguaggio (in-built)
e quelli definiti dal programmatore (user-defined).
Tra i tipi nativi, il tipo int identifica una variabile che memorizza
un valore intero con segno.
A differenza del Matlab le variabili devono sempre essere dichiarate
e (a differenza del Fortran) possono essere dichiarate ovunque (ma
prima di essere utilizzate).
27/1
Identificatori
Un nome di variabile (o di funzione) deve essere un valido
identificatore. Un identificatore in C++ è una successione di
caratteri alfanumerici in cui il primo carattere è alfabetico. È
ammesso il carattere underscore (_), anche come primo carattere.
Il linguaggio distingue lettere maiuscole da minuscole: pippo è un
identificatore diverso da Pippo.
Un identificatore NON può essere uguale a una parola chiave
(keyword). La lista delle parole chiavi del C++ (in tutto 74) è
contenuta a pag. 20 del libro di testo.
28/1
Oggetti, variabili, espressioni
Un oggetto (object) è un area di memoria capace di memorizzare
un valore di un certo tipo.
Una variabile (variable) è un oggetto con un nome anche se talvolta
si indica con unnamed variable un oggetto senza nome.
Un operatore è una particolare istruzione che combina uno o due
argomenti (in un caso speciale tre) e ritorna un risultato (es. il + in
a+b;).
Una espressione è una combinazione di oggetti, espressioni ed
operatori che producono un valore di un certo tipo. Per esempio
a+5 è una espressione che, se a è un int produce un valore di tipo
int .
Una espressione è composta se è formata dalla combinazione di
sottoespressioni, per esempio a + b∗c è formata da a e b∗c. Una
espressione è costante se il suo valore non può essere modificato (in
generale).
29/1
L’input/output (formatted)
#include <iostream>
..
std::cout « ’’Dammi due interi:’’ « std::endl;
std::cin » n » m;
Uno stream può essere immaginato come una sorgente o un
“pozzo” di dati (tipicamente caratteri), usualmente associati a
lettura/scrittura da file o teminale.
La standard template library attraverso il modulo iostream mette
a disposizione 4 stream per i/o da/su terminale:
std::cin
std::cout
std::cerr
std::clog
Standard
Standard
Standard
Standard
Input (buffered)
Output (buffered)
Error (unbuffered)
Logging (default è = cout)
30/1
Tipi di variabili
I principali tipi nativi forniti dal linguaggio sono
float
Numero reale in singola precisione (4 bytes)
double
Numero reale in doppia precisione (8 bytes)
long double Numero reale in precisione estesa (8 o 16 bytes)
int
Intero con segno (tip. 4 bytes)
short int
Intero corto con segno (tip. 1 byte)
long int
Intero esteso con segno (tip. 8 bytes)
bool
Variabile logica (impl. dip.)
char
Carattere (1 byte)
unsigned
Prefisso per interi positivi
31/1
Numeri a virgola mobile (floats)
Tipicamente le variabili float obbediscono allo standard IEEE.
Il C++ permette però di controllare i limiti numerici ed in
particolare di trovare l’epsilon macchina per i vari tipi a virgola
mobile. Si deve usare il modulo della Standard Template Library
<limits>.
#include <limits>
...
std::numeric_limits<float>::epsilon();
std::numeric_limits<float>::max();
Si veda anche l’esempio in examples/numeric_limits.
32/1
Rappresentazione dei numeri a virgola mobile
Un sistema di numerazione floating point (normalizzato) F è
definito dai numeri reali rappresentabili nella forma
y = ±m × β e−t
β
m
base (tipicamente 2)
mantissa, 0 ≤ m ≤ β t − 1
t
e
precisione
esponente, emin ≤ e ≤ emax
Analogamente
y = 0.d1 d2 ...dt × β e
d1 6= 0,
0 ≤ di ≤ β − 1
I numeri rappresentabili in un computer appartengono a
F ∗ = F ∪ Fs dove Fs è il set dei numeri subnormali, della forma
y = ±m × β emin −t ,
0 < m < β t−1
33/1
Arrotondamento
Un numero reale x ∈ range(F ∗ ) è rappresentato nel computer da
x̂ = fl (x) ∈ F ∗ e |x − x̂|/x è l’errore di arrotondamento (relativo).
Se x ∈ range(F ∗ ) allora x̂ = fl (x) ∈ F e
x − x̂
= ∆,
x
1
con |∆| ≤ u = β 1−t
2
u è detto roundoff unit ed è legato all’epsilon macchina M da
1
u = M . Si ricorda che M è il minimo numero positivo per cui
2
fl (1 + M ) 6= 1.
Nota: 0 ∈ F .
34/1
Aritmetica IEEE
Lo standard IEEE 754 è stato definito nel 1985 e definisce un
sistema aritmetico a virgola mobile oramai comunemente
implementato nei normali microprocessori. Definisce due tipi
principali di floating point: singola precisione (float) e doppia
precisione (double).
Type
Size
t
e
u
Range
float
double
32
64
23 + 1
52 + 1
8
11
2−24
2−53
10±38
10±308
I numeri rappresentano i bits usati.
Soddisfa inoltre il modello standard: se x, y ∈ F allora
fl (x op y ) = (x op y )(1 + δ) |δ| ≤ u,
op = + − ×, /
35/1
Numeri speciali
Lo standard IEEE stabilisce che
fl (x) = 0 se|x| < Fmin
(UNDERFLOW)
Fmin ∈ F ∗ essendo il minimo numero positivo rappresentabile.
fl (x) = sign(x)Inf
se|x| > Fmax
(OVERFLOW)
Fmax ∈ F essendo il massimo numero rappresentabile. Inoltre
x/0 = ±Inf se x 6= 0, Inf + Inf = Inf e x/Inf = 0 se x 6= 0.
NaN indica il risultato di una operazione illecita (0/0, log(0) etc).
Inoltre x op NaN = NaN, Inf − Inf = NaN e 0/Inf = NaN.
36/1
Forward and backward error
Sia f : R → R e fˆ : F → F l’equivalente espressione operante su
numeri a virgola mobile. Sia y = f (x) e ŷ = fˆ(x̂). L’analisi del
forward error si propone di trovare un δ tale che
|y − ŷ |
≤δ
|y |
Il backward error (relativo) ∆ e definito da ŷ = f (x(1 + Delta)). Se
f ∈ C 2 ha che
y − ŷ
= c(x)∆ + O((∆x)2 )
y
|c(x)| è detto numero di condizionamento. Normalmente ne viene
fornita una stima
δ ≤ C (x)|∆|
37/1
Un esempio: la cancellazione
Consideriamo y = f (a, b) = a − b e ŷ = f (a(1 + ∆), b(1 + ∆)).
Dopo semplici calcoli
|
|a∆ − b∆|
|a| + |b|
|a| + |b|
y − ŷ
|=
≤
∆⇒C =
y
|a − b|
|a − b|
|a − b|
Abbiamo che C → ∞ quando |a − b| → 0: sottrazione di due
quantità molto vicine causa un forte errore di arrotondamento. E‘
quindi una operazione da evitare!
38/1
Calcolo della radice di una quadratica
Gli zeri di ax 2 + bx + c possono essere calcolati con la formula
classica
√
−b ± b2 − 4ac
x1,2 =
2a
√
Ma cosa succede se b >> 4ac o se b ' 2 ac?
Si veda examples/QuadraticRoot
39/1
Ritorno al linguagggio C++: i char
char p=’A’;
char q=’\n’;
Un carattere è individuato da gli apici singoli. Vi sono dei caratteri
speciali, quali ’\n’. Quest’ultimo indica andare a capo (carriage
return).
Una variabile char contiene un singolo carattere. Vedremo in
seguito come trattare le stringhe di caratteri.
40/1
bool
bool l=true;
bool s;int a=5;
s= (a==5); //s è pari a true
La variabile bool può assumere solo due valori, vero o falso,
indicati dalle due parole riservate true e false. Si può usare in
alternativa 1 e 0.
Le variabili bool vengono usualmente utilizzate per memorizzare il
risultato di espressioni logiche.
41/1
Principali operazioni
i=g+g; La somma (+), moltiplicazione (*) etc. sono definite per
tutti i tipi numerici.
a=pow(3.5,4). (3.5)4 . Richiede <cmath>.
a*=5. Equivalente a a=a*5. Ma più efficiente. In generale op ha
anche l’equivalente op=
++i e i++. Preincremento e post-incremento. Entrambe pari a
i = i + 1 ma la seconda ritorna il valore di i prima dell’incremento.
--i e i--. Come sopra ma decrementando di 1.
Operatori logici: &&, || e !.
Test logici: ==, !=, <, <= etc.
42/1
Dichiariazione e definizione di variabile
Questi termini sono di suo comune e vengono spesso confusi.
I
Dichiarazione. Associa un tipo a un nome di variabile.
Permette al compilatore di determinare la dimensione di un
oggetto di quel tipo.
I
Definizione. Indica come una variabile viene costruita (e ne
definisce le sue funzionalità). Rilevante per tipo definiti
dall’utente.
I
Istanza. Momento in cui una variabile viene costruita in
memoria e viene creato un oggetto.
I
Inizializzazione. Assegnazione di un valore iniziale a una
variabile (spesso coincide temporalmente con l’istanza)
I
Assegnazione Attribuisce a una variabile già istanziata in
precedenza un valore, usualmente attraverso l’operatore di
assegnazione =.
43/1
Inizializzazione di variabili
Per i tipi nativi la dichiarazione implica anche l’istanzazione della
variabile (a meno che non si usi la keyword extern) e
l’inizializzazione (a meno che la variabile non sia membro di una
struct o classe)
extern int z; Dichiarazione
int a; Dichiarazione (e istanziazione/inizial.)
float b=3.14; Inizializzazione
float c(3.14); Inizializzazione
float e=atan(1)*4; Inizializzazione
long int=3L; Inizializzazione
a=10; Assegnazione
Nota: Non assumere mai che una variabile sia inizializzata
automaticamente a un valore: inizializzatela sempre esplicitamente.
44/1
Alcune regole importanti
• Una variabile deve sempre essere dichiarata prima di poter essere
riferita in altre parti del programma.
• Una variabile può essere dichiarata più volte, purchè la
dichiarazione sia identica.
• Una variabile può essere definita una sola volta. La variabile è
accessibile solo dopo la sua definizione.
• La definizione è anche una dichiarazione.
45/1
Unitd̀i compilazione
Un programma C++ è normalmente contenuto in più file sorgente
(source files), con estensione .cpp, o .cxx. Solo nei casi più
semplici vi è un solo file.
Un file sorgente può includere degli header files, tipicamente con
estensione .hpp o .h.
Un file sorgente insieme agli header files eventualmente inclusi,
forma una compilation uniti (unità di compilazione).
Il compilatore compila ciascuna unità di compilazione
separatamente. Sarà poi il linker a mettere insieme le informazioni
fornite da ciascuna unità di compilazione e produrre l’eseguibile.
46/1
Le istruzioni di controllo e i cicli
if (n > m) {
...Blocco di istruzioni
}...
for (int i = n; i <= m; i++) sum+=i
Il linguaggio prevede istruzioni di controllo: if{...}else{...} e di
ciclo: for(){...}, do{...} while().
47/1
Ciclo for
for(init;test;update) {
corpo (body)
..}
48/1
Ciclo for
for(init;test;update) {
corpo (body)
..}
init è una istruzione che viene eseguita all’inizio del ciclo,
tipicamente per inizializzare una variabile locale, per esempio int
i=0.
48/1
Ciclo for
for(init;test;update) {
corpo (body)
..}
test. Una espressione logica che viene eseguita all’inizio del corpo
del ciclo. Se è vera le istruzioni nel corpo vengono eseguite. Es.:
i<10.
48/1
Ciclo for
for(init;test;update) {
corpo (body)
..}
update è una istruzione che viene eseguita alla fine del corpo del
ciclo. Es.: ++i.
48/1
Ciclo for
for(init;test;update) {
corpo (body)
..}
Le variabili definite nel ciclo sono locali al ciclo:
i=90;
for(int i=0;i<=10;++i) ...
cout«i; // i qui vale 90
48/1
Conversioni tra variabili di tipo diverso
int a=5; float b=3.14;double c,z;
c=a+b
c=double(a)+double(b) (conv. per costruzione)
z=static_cast<double>(a) (conv. per casting)
Il C++ prevede una serie di regole per la conversione implicita tra
tipi “nativi”.
È possibile anche indicare esplicitamente la conversione, come
indicato sopra.
Nota: È meglio, per la leggibilità del codice, usare sempre
conversioni esplicite.
49/1
Conversioni particolari
int a=5; char A=’A’
bool c=bool(a); non serve la conver. esplicita
float b=3.14;
c=b; c è pari a true
a=A; a è il codice ASCII di ’A’
Vi è la regola che ogni valore non nullo di variabili intere e a virgola
mobile e ogni carattere diverso dal carattere nullo sono convertiti in
true.
Analogamente, in una espressione logica, il puntatore nullo viene
convertito a false, mentre ogni altro puntatore a true.
Nota: Questa regola si rivelerà molto utile.
50/1
Conversione per casting statico
La conversione per casting statico è più efficiente perchè non crea
temporanei:
float a=10; double b=static_cast<double>(a);
La variabile a è reinterpretata come double e il valore viene usato
per inizializzare b
float a=10; double b=double(a);
Una variabile temporanea di tipo double viene costruita copiando
da a a e quindi assegnata a b.
51/1
Due modalità per i commenti
i n t a =0; // Commento i n l i n e a
b=s t d : : s q r t ( 5 . 0 ) ;
/∗ Commento s u p i ù l i n e e
È e r e d i t a t o d a l C ∗/
....
Esistono delle tecniche di documentazione (si veda il programma
DoxyGen (che useremo negli esercizi)) che permettono di produrre
automaticamente il manuale di riferimento processando il codice
sorgente usando delle keyword particolari all’interno dei commenti.
È importante commentare il codice e i commenti devono essere
significativi, cioè aiutare chi utilizza il codice a comprenderne il
funzionamento.
52/1
Lo scope (ambito di visibilità)
Lo scope (ambito di visibilità) di una variabile (o una funzione)
definisce la porzione di programma in cui la variabile (o funzione) è
visibile, cioè può essere utilizzata usando il suo nome.
Una variabile non in scope può essere tuttavia accessibile usando il
suo full qualified name attraverso lo scope resolution operator ::
(ne parleremo più in dettaglio più avanti...).
..
int x=10;//variabile globale
int main(){
int x=20;//variabile locale
cout « x« ::x;
... }
53/1
• Ogni parte di programma racchiusa tra parentesi graffe identifica
uno scope separato. Eccezione: nella istruzione if {...} else {
...} le due (o più) coppie di parentesi graffe identificano lo stesso
scope.
• Gli scope sono annidati tra loro, e uno scope “interno” eredita le
definizioni delle variabili di quello esterno.
• Il nome di una variabile (o funzione) dichiarata in uno scope
nasconde una variabile o funzione dichiarata in uno scope più
esterno (name hiding o shading).
• Lo scope più esterno è detto globale.
• L’operatore :: (scope resolution operator) permette di accedere
a variabili/funzioni globali.
• Le istruzioni di ciclo for, while etc. definiscono uno scope, che
include la parte che concerne il test.
• Una variabile istanziata in uno scope è locale a tale scope.
• Una variabile viene distrutta alla termine dello scope in cui è
stata istanziata (a meno che non sia dichiarata static, come si
vedrà in seguito).
54/1
Visibilità ed esistenza
Il termine scope riferito a un oggetto spesso viene usato anche con
il significato di ambito di esistenza.
L’ambito di esistenza di un oggetto è la porzione del codice in cui
l’oggetto esiste. Inizia al momento della istanza e termina quando
viene chiamato il distruttore dell’oggetto.
Manterremo l’ambiguità del temine che dovrà essere interpretato
correttamente dal contesto.
55/1
Array (monodimensionali)
double a[5]={1.6,2.7,3.4,7,8};
b=a[0]+a[3];//b vale 8.6
int c[2]; c[0]=7; c[1]=8;
In C++ gli array vengono indirizzati a partire da 0 usando
l’operatore [].
Un’alternativa: usare i vector<> della Standard Template Library
#include <vector>
vector<double> a;
a.push_back(1.6)\1.6 -> a[0]
56/1
vector<T>
I vector della standard library sono un esempio di template di cui
parleremo estensivamente in una prossima lezione.
Sono dei contenitori generici che implementano l’indirizzamento
diretto tramite l’operatore [].
#include <vector>
using std::vector
vector<unsigned int> a(5);
a[2]=9;
...
a[0]+=a[2];
...
57/1