Riepilogo
Questa lezione apre la terza unità del corso, dedicata alle espressioni e ai loro operatori. Spiega a che cosa serve l’unità: insegnare a costruire espressioni il cui valore si possa prevedere con certezza, sapendo quale operazione si esegue per prima, di che tipo è il risultato, quali effetti collaterali hanno e quali espressioni non hanno significato; presenta le sue quattro lezioni e il filo che le unisce, dall’aritmetica intera e reale fino ai bit e alla libreria matematica, passando per le condizioni e per il catalogo del comportamento indefinito; ricorda ciò che l’unità dà per scontato della seconda, cioè il tipo di ogni dato, i suoi limiti e le sue conversioni; formula il problema che l’unità risolve, quello di un programma che compila senza un solo avviso e le cui risposte a sei domande scolastiche sono tutte sbagliate, quando non mancano del tutto; e mostra dove conduce, nelle unità successive e nel corso Programmazione in C++ II.
Obiettivi di apprendimento
- Descrivere la sequenza dei contenuti dell’unità e spiegare che cosa apporta ciascuna lezione alla successiva.
- Ricordare il necessario dell’unità 2 (i tipi interi e reali, i loro intervalli, l’overflow e le conversioni) e ripassarlo se occorre.
- Anticipare, con un esempio, che il valore di un’espressione dipende da regole di valutazione (la precedenza, il tipo degli operandi, l’ordine degli effetti) che non sempre coincidono con quelle della matematica scolastica.
- Riconoscere che cosa ci si aspetta di saper fare alla fine dell’unità, e distinguerlo da ciò che si imparerà nelle unità successive.
Valutazione d’ingresso
Prima di percorrere l’unità conviene misurare il punto di partenza. Questa valutazione è un’autovalutazione: non ha voto, e il suo unico scopo è orientare lo studio. Le prime quattro domande verificano ciò che l’unità dà per scontato della seconda: la divisione tra interi, la scrittura in base 2, la sottrazione senza segno e l’overflow con segno. Le sei successive toccano, nell’ordine delle lezioni, le idee centrali dell’unità, e varie di esse partono dalla matematica scolastica o dalla logica elementare. Nessuno è tenuto a indovinarle già, e in due di esse «non lo so ancora» è una risposta onesta: ogni risposta, giusta o no, spiega il punto e nomina la lezione che lo tratta. Le stesse abilità si misurano di nuovo alla fine, nella lezione di sintesi.
Prima di iniziare l’unità, misura il tuo punto di partenza. È un’autovalutazione breve: non riceve voto e il risultato resta solo nel tuo browser.
Domanda 1Dalle unità precedentiUn programma dichiara
const double r{7 / 2};e scriver. Che cosa appare?Crede che il tipo della variabile decida come si divide; lo decide il tipo degli operandi.Crede che la divisione intera arrotondi; scarta la parte decimale.Il valore 3 è costante e si rappresenta esattamente in undouble: non c’è nessun restringimento da rifiutare.La divisione7 / 2è tra interi e dà il quoziente intero, 3; solo dopo quel 3 viene convertito indouble. Il tipo degli operandi decide l’operazione, non il tipo della variabile che riceve il risultato. La lezione 3.1 trasforma questa osservazione in una regola generale: il tipo si decide in ogni nodo dell’espressione.Ripassare: Caratteri, booleani, conversioni e costanti
Domanda 2Dalle unità precedentiCome si scrive il numero 13 in base 2, con otto bit?
Somma male i pesi: .Scrive i resti delle divisioni successive nell’ordine in cui escono; si leggono dall’ultimo al primo.Quella configurazione è 26, il doppio di 13: i bit sono spostati di una posizione.Ogni posizione pesa il doppio di quella alla sua destra: gli uno occupano le posizioni di peso 8, 4 e 1. La lezione 3.4 opera direttamente su questi bit, sicché conviene leggerli con scioltezza.Ripassare: Gli interi e la loro rappresentazione
Domanda 3Dalle unità precedentiChe cosa scrive
std::println("{}", 0u - 1);con ununsigned intdi 32 bit?Non tiene conto del suffissou: un tipo senza segno non ha negativi.Confonde l’aritmetica senza segno, definita modulo , con l’overflow con segno.Crede che la sottrazione si fermi al valore minimo del tipo; fa il giro.L’aritmetica senza segno è modulo : . Il risultato è definito, e per questo nessun sanitizer lo segnala. L’unità lo ritrova nelle conversioni di un’espressione mista e negli operatori bit a bit, che si scrivono con tipi senza segno.Ripassare: Gli interi e la loro rappresentazione
Domanda 4Dalle unità precedentiUn programma esegue
int count{std::numeric_limits<int>::max()};e poicount = count + 1;. Che cosa garantisce lo standard sul valore dicount?Confonde ciò che si osserva a volte con ciò che lo standard garantisce; il ritorno al minimo è ciò che fanno i tipi senza segno, non quelli con segno.Ignora il limite del tipo: quel numero non sta in unintdi 32 bit.Il compilatore non conosce i valori che il programma avrà durante l’esecuzione; quasi sempre compila senza dire nulla.La somma ha una precondizione, che il risultato stia nel tipo, e al di fuori di essa lo standard non promette nulla. Il sanitizer del corso arresta il programma; senza di esso, può essere scritta qualunque cosa. La lezione 3.3 riunisce questo caso con gli altri della sua specie in un catalogo.Ripassare: Gli interi e la loro rappresentazione
Domanda 5Quanto valgono e ?
Opera da sinistra a destra senza badare alla precedenza del prodotto.Ignora le parentesi della seconda espressione.Attribuisce a ciascuna espressione il valore dell’altra: inverte l’effetto delle parentesi.Il prodotto lega più della somma: in si moltiplica per prima cosa, e le parentesi alterano quell’ordine. C++ segue la stessa convenzione, e la lezione 3.1 la estende alla divisione, al resto e all’associatività, con l’albero dell’espressione come strumento.Ripassare: Aritmetica
Domanda 6Secondo il teorema della divisione della matematica, con il resto soggetto a , quali sono il quoziente e il resto di diviso ?
È ciò che calcola C++, ma non soddisfa : il resto della matematica non è negativo.Non verifica l’identità: , non .Neppure soddisfa l’identità: .Il teorema esige con , e quei due numeri sono gli unici che lo soddisfano. C++, invece, tronca il quoziente verso lo zero:-7 / 2vale e-7 % 2vale . La lezione 3.1 spiega la differenza e insegna a ottenere il resto della matematica a partire da quello di C++.Ripassare: Aritmetica
Domanda 7Qual è la negazione di «piove e fa freddo»?
Nega ciascuna parte senza cambiare il connettivo: questo afferma molto più della negazione, perché esclude anche il giorno asciutto e freddo.Nega solo una delle parti.Dice lo stesso della seconda opzione, con lo stesso errore.La negazione di una congiunzione è la disgiunzione delle negazioni: è una delle leggi di De Morgan. Basta che manchi una delle due cose perché l’affermazione sia falsa. La lezione 3.2 applica la stessa legge alle condizioni di un programma.Ripassare: Relazioni e logica
Domanda 8Che cosa scrive
std::println("{}", 3 < 5);?Crede che il valore logico si scriva come numero; con il segnaposto{},std::printlnscrive la parola.Crede che l’espressione si scriva come testo; ciò che si scrive è il suo valore.Lo è: un confronto è un’espressione di tipobool.Un confronto è un’espressione come qualsiasi altra: ha un valore, di tipobool, estd::printlnlo scrive cometrueofalse. La lezione 3.2 parte da questa osservazione: una condizione si calcola, e perciò ha precedenza, albero e algebra.Ripassare: Relazioni e logica
Domanda 9Dopo
int a{5};eint b{a++ * 2};, quanto valgonoaeb?È una risposta onesta: la lezione 3.3 insegna la differenza tra il valore di un’espressione e il suo effetto, e la valutazione d’uscita tornerà a chiederlo.Dimentica l’effetto:a++incrementaa.Usa il valore nuovo dia; l’incremento postfisso dà il valore precedente.L’espressionea++ha un valore, quello cheaaveva (5), e un effetto, che lasciaaa 6. Il prodotto usa il valore, non l’effetto. La lezione 3.3 insegna a separare le due cose, e a riconoscere quando due effetti in una stessa espressione la lasciano senza significato.Ripassare: Assegnamento, effetti collaterali e comportamento indefinito
Domanda 10Che cosa scrive
std::println("{}", 2 ^ 3);?È una risposta onesta: la lezione 3.4 lo spiega, e la valutazione d’uscita tornerà a chiederlo.Legge l’accento circonflesso come potenza, come nella notazione di molte calcolatrici; in C++ non lo è.Lo legge come prodotto.In C++ l’accento circonflesso non è la potenza, ma lo XOR bit a bit: e differiscono solo nel bit di peso 1, sicché il risultato è 1. C++ non ha un operatore di potenza; la lezione 3.4 insegna quando usarestd::powe quando uno scorrimento.Ripassare: Bit e libreria matematica
Caricamento del contenuto…