Skip to content
This repository has been archived by the owner on Jun 16, 2023. It is now read-only.

Commit

Permalink
fine lezione 13
Browse files Browse the repository at this point in the history
  • Loading branch information
mc-cat-tty committed Nov 4, 2021
1 parent 138f54f commit b92f458
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 0 deletions.
Binary file removed .12_float_double.md.swp
Binary file not shown.
8 changes: 8 additions & 0 deletions 12_float_double.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,11 @@ Tipicamente il float (4 byte) hanno un precisione di 6 cifre decimali, mentre il

## Rappresentazione dello zero
La mantissa, per definizione ha la prima cifra diversa da zero, quindi 0 non sarebbe rappresentabile -> se tutti i bit sono esattamente a zero, il numero complessivo è considerato come zero.

## Confronto approssimato
Hint: usa range quando fai confronti tra numeri reali per far fronte ad eventuali errori di approssimazione dovuti alla memorizzazione dei numeri float e double.

## exit
Per uscire dal programma in qualsiasi punto di esso si può chiamare la funzione `void exit(int n)`

Warning: l'operatore `%` non esiste per float e double
105 changes: 105 additions & 0 deletions 13_compendio_tipi_dato.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Unsigned, short e long

Tipi interi:
|nome|dimensione|
-----------------
|int|32 bit|
|short int|16 bit|
|long int|64 bit|

Tipi naturali (no numeri negativi):
Stessa dimensione dei tipi non-unsigned, ma i valori rappresentabili raddoppiano, in quanto sono memorizzabili solo valori maggiori o uguali a zero

## long
=> usando il modificatore `long` viene assicurato che la dimensione sia almeno pari a quella degli int

## long long
Dato che la dimensione del tipo int dipende dalla word del calcolatore, dallo standard C++11 è stato introdotto il modificatore `long long int` -> almeno dimensione degli int, non meno di 64 bit

## Tipo carattere
char, signed char e unsigned char occupano tutti 8bit
Il char può essere signed o unsigned di default in base all'implementazione

## Tipo float
|nome|dimensione|
----------------
|float|32 bit|
|double|64 bit|
|long double|80 bit (10 bytes)|

## Espressioni letterali
Mediante i seguenti suffissi è possibile comunicare esplicitamente al compilatore il tipo di dato di un letterale:
U unsigned int
UL unsigned long
ULL unsigned long long
L long int
LL long long int

## Overflow di un unsigned
Cosa succede se decremento il valore 0? Overflow

Eg:
MAX_UINT + 1U = 0
0U - 1U = MAX_UINT
MAX_UINT + 2U = 1

## Limits
`#include <limits.h>`

`numeric_limits<nome_tipo>::`
min()
max()
digits numero cifre in base 2
digits10 numero cifre in base 10
is_signed se ammette valori negativi
is_integer true se è un tipo discreto

TODO: completa da slide a pagina 91, link: https://algogroup.unimore.it/people/paolo/courses/programmazione_I/vecchie_edizioni/edizione_2021/materiale_2021/lezioni/Cap_10-Enum-reali-conv-tipo.pdf

epsilon() minimo valore tale che 1+epsilon != 1 -> precisione del tipo di dato
round_Error() errore arrotondamento

## Espressioni eterogenee
Ogni qualvolta siamo in presenza di operazioni che coinvolgono operandi di diverso tipo
Soluzione:
- conversioni esplicite del programmatore
- conversioni implicite del compilatore (coercion)

Le conversioni implicite non sono illegali, ma avvengono secondo una certa lista di regole (tipicamente il compilatore le segnala con warning)

La conversione implicita avviene verso tipi di dato di gerarchia superiore. Il risultato sarà di questo tipo di dato.
Gerarchia: char < int < float < double < long double
Il tipo unsigned è di gerarchia superiore rispetto al tipo signed
Questo avviene in modo ripetuto per ogni espressione, secondo la priorità dell'operazione (eg: somma di prodotti)

## Assegnamento eterogeneo
- Se var è di ordine superiore all'espressione, quest'ultima viene convertita al tipo di dato della variabile. No perdita informazione (eg: double = char)
- Se var è di ordine inferiore all'espressione, avviene conversione con probabile perdita di informazione.

Esempi:
int a, b=2; float x=5.8;
a = b + x // == 7
Equivalente all'operazione implicita: `a = static_cast<int>(static_cast<float>(b) + x)`

Memorizzare un float in un int potrebbe portare ad una perdita di informazioni, perchè il valore massimo rappresentabile da un float è maggiore di quello memorizzabile da un intero.
Memorizzare un intero in un float potrebbe portare ad una perdita di informazione, in quanto la precisione di float e double è inferiore al numero di cifre garantite da float e double.

## cmath con i reali
`double fabs(double x);` -> valore assoluto di un numero reale
`double ceil(double x);` -> minimo intero maggiore di x
`double floor(double x);` -> massimo interno minore di x

## ctype con caratteri
Le seguenti funzioni ritornano 0 se falso, un numero intero altrimenti:
`int isalnum(int c)` -> se alfanumerico
`int isalpha(int c)` -> se alfabetico
`int isdigit(int c)` -> se carattere decimale
`int isxdigit(int c)` -> se carattere esadecimale
`int islower(int c)` -> se carattere minuscolo
`int isupper(int c)` -> se carattere maiuscolo

`int tolower(int c)` -> converte il carattere in minuscolo
`int toupper(int c)` -> converte il carattere in maiuscolo


TODO: esercizi https://algogroup.unimore.it/people/paolo/courses/programmazione_I/vecchie_edizioni/edizione_2021/materiale_2021/esercitazioni/lab7_visib_car_reali/Compiti%20per%20Casa/
50 changes: 50 additions & 0 deletions 13_ingegneria_del_codice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Ingegneria del codice

Obiettivi -> codice:
- leggibile
- robusto
- manutenibile

## Principi ingegneria del codice

1. il codice deve essere formattato in modo opportuno (indentazione e spaziatura)
2. usare nomi significativi per le variabili
3. usare strutture dati chiare
4. anche le funzioni devono avere un nome significativo
5. cercare di raggruppare concetti correlati (separare i gruppi di variabili per concetto, utilizzare più andate a capo per separare blocchi di codice logicamente separati)
6. non duplicare il codice (replicare il codice porta ad uno sviluppo, testing e manutenzione in parallelo, quindi fonte di errori). Lasciare codice duplicato solo se renderlo modulare complica di più le cose.
7. riutilizzare il codice già disponibile, ma con spirito critico. Non reinventare la ruota
8. usare un corretto livello di astrazione. Usare nomi significativi appartenenti al dominio del problema
9. scegliere un tipo di dato appropriato
10. aggiungere commenti
11. non fare assunzioni

Hint: progettare il codice in anticipo e renderlo facilmente estensibile, mantenendo il codice modulare

Hint: se puoi usa i double, a meno che non si stia sviluppando su un ambiente memory-constrained

## Complessità
- complessità/costo computazionale: misura il costo di un algoritmo in termini di passi elementari per arrivare alla soluzione
- complessità e funzioni: difficoltà richiesta da un frammento di codice per essere compreso (numero variabili da tenere a mente...)

Attenzione agli effetti collaterali: minimizzare passaggi per riferimento (senza const) e variabili globali, numero scelte e cicli (strutture di controllo), soprattutto se nidificate (non andare oltre 3 livelli di nidificaizone)
Come ridurre le nidificazioni? inserire cicli e controlli all'interno di funzioni

### Formattazione
Riduci il numero di colonne utilizzato per scrivere il programma. Mantieni sotto le 80 colonne (i vecchi terminali erano larghi 80\*64)

### Commenti
Usa commenti, il giusto numero. Per le funzioni descrivi varibili aspettate, parametri ingresso e uscita, descrivi brevemente la funzione e se ci sono effetti collaterali. Non scrivere quello che il codice fa perchè è palese dedurlo dallo stesso.

## Warning
`g++ -Wall source.cpp` per abilitare tutti i warning
`g++ -Wall -pedantic source.cpp` per un livello di maggior sensibilità (disabilita estensioni del linguaggio C/C++, facendo emergere più warning)
`g++ -Wall -Werror source.cpp` trasforma i warning in errori che bloccano la compilazione

Torvald's rants: https://github.com/corollari/linusrants
Comments coding style: https://lwn.net/Articles/694755/

## Coding style
Mantenere un coding style consistente


38 changes: 38 additions & 0 deletions 13_passaggi_per_riferimento.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Passaggi di parametri per riferimento
Esempio di problema: vogliamo scambiare due variabili all'interno di una funzione, portando le modifiche all'esterno di essa (scambiare il valore dei parametri attuali)

Per superare i limiti della semantica per copia occorre utilizzare il passaggio di varibili per riferimento. Se una funzione dichiara (nella sua intestazione) che un parametro costituisce un riferimento, allora il parametro formale non è più una variabile locale, bensì un riferimento alla variabile passata come parametro attuale. Le modifiche a questo riferimento si propagano fuori dalla funzione stessa.

Il passaggio per riferimento è disponibile in molti linguaggi, ma non in C: necessario usare i puntatori (tipo derivato riferimento).

Un riferimento è un identificatore associato all'indirizzo di una variabile (di un oggetto) e non al valore della stessa.

Quando si dichiara un oggetto, gli si assegna un riferimento di default, quello che fin'ora abbiamo chiamato nome dell'oggetto.

## Sintassi riferimento
`<definizione_riferimento> ::= <tipo_riferimento> <identificatore> = <nome_oggetto>;`
`<tipo_riferimento> ::= <tipo_oggetto> &`

È equivalente ad assegnare un'ulteriore etichetta (alias) ad un identificatore già definito -> l'inizializzazione di un riferimento è obbligatoria all'atto della sua definizione

Una volta definito e inizializzato, un riferimento si riferisce sempre allo stesso oggetto.

Il modificatore `const` proibisce la modifica del valore associato al riferimento

Ogni modifica fatta sul riferimento verrà fatta anche sull'oggetto originale.

## Effetti collaterali
I passaggi per riferimento e l'utilizzo di variabili globali sono i due meccanismi che ci consentono di avere effetti collaterali.
=> permettono interazione tra diverse parti del programma

Attenzione: rendono il programma più difficilmente debuggabile

## Parametri di input e output
Posso avere:
- parametri solo di ingresso oggetti usati esclusivamente il lettura
- parametri solo di uscita oggetti mai usati in lettura, ma solo per memorizzare il valore di ritorno
- parametri di ingresso/uscita oggetti letti e poi sovrascritti con risultato

=> questo mi permetti di avere più valori di uscita dalla funzione (un solo valore di ritorno sempre e comunque).

Hint: buona prassi commentare le funzioni (comportamento e utilizzo dei parametri).
Binary file removed esercitazioni/.ascensore.cpp.swp
Binary file not shown.
17 changes: 17 additions & 0 deletions esercitazioni/moltiplica.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>

using namespace std;

void moltiplica(int&, int);

int main() {
int x, y;
cin >> x >> y;
moltiplica(x, y);
cout << x;
return 0;
}

void moltiplica(int &a, int n) {
a *= n;
}

0 comments on commit b92f458

Please sign in to comment.