In realtà l’errore che viene commesso non è di carattere informatico, ma puramente matematico, dimenticando l’ordine con cui vengono eseguite le operazioni matematiche.
L’ordine delle operazioni segue le regole di base: moltiplicazioni e divisioni hanno precedenza massima seguono addizioni e sottrazioni. Se si vuole cambiare l’ordine di precedenza bisogna utilizzare le parentesi. Vediamo alcuni esempi.
int valore = 1 + 2 * 3 + 4;
il risultato sarà 11.
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 01: Ordine di esecuzione operazioni matematiche in C
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo:");
Serial.println("valore = 1 + 2 * 3 + 4");
int valore = 1 + 2 * 3 + 4;
Serial.print("valore = ");
Serial.println(valore);
abilitaMessaggio = 1;
}
}
Per rendere più evidente la sequenza di esecuzione del calcolo possiamo usare le parentesi, pertanto otterremo:
int valore = 1 + (2 * 3) + 4;
Che fornisce sempre il valore 11.
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 02: Ordine di esecuzione operazioni matematiche in C
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo:");
Serial.println("valore = 1 + (2 * 3) + 4");
int valore = 1 + (2 * 3) + 4;
Serial.print("valore = ");
Serial.println(valore);
abilitaMessaggio = 1;
}
}
Per modificare la precedenza utilizziamo le parentesi:
int valore = ((1 + 2) * 3) + 4;
il risultato sarà 13. Viene eseguito prima il calcolo della parentesi più interna (1+2), poi si passa alla parentesi immediatamente successiva, quindi (3 * 3) e poi il risultato viene sommato a 4.
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 03: Ordine di esecuzione operazioni matematiche in C
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo:");
Serial.println("valore = ((1 + 2) * 3) + 4");
int valore = ((1 + 2) * 3) + 4;
Serial.print("valore = ");
Serial.println(valore);
abilitaMessaggio = 1;
}
}
Ovviamente, come già spiegato precedentemente, bisognerà sempre fare attenzione che il risultato faccia parte del tipo di dati giusto, ad esempio quando effettuate una divisione tra interi il cui risultato è un numero decimale, o ancora se superate il valore massimo del tipo di dato che state utilizzando. In entrambi i casi il compilatore non vi segnalerà nessun errore.
Vediamo un esempio:
// 60 secondi in un minuto, 60 minuti in un'ora, 24 ore in un giorno
long secondi_in_un_giorno = 60 * 60 * 24;
In teoria, poiché il risultato è 86.400, questo valore potrà essere contenuto in un tipo long.
Ma in realtà il valore realmente memorizzato in “secondi_in_un_giorno” è 20.864.
86.400 supera più di due volte la dimensione di un intero, il calcolo fatto dal compilatore sarà il seguente:
86.400 – 32.768 * 2 = 20.864
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 04: Ordine di esecuzione operazioni matematiche in C
// errore di calcolo dovute al tipo del dato (dimensione massima).
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo (errato) numero di secondi in un giorno:");
Serial.println("secondi_in_un_giorno = 60 * 60 * 24");
long secondi_in_un_giorno = 60 * 60 * 24;
Serial.print("Secondi in un giorno = ");
Serial.println(secondi_in_un_giorno);
Serial.println("Errore! Il valore doveva essere: 86.400");
Serial.println("L'errore si verifica perchè il compilatore considera i numeri di tipo int.");
abilitaMessaggio = 1;
}
}
Ciò accade perché il compilatore C dell’IDE di Arduino vede un’espressione aritmetica composta da soli numeri interi e quindi considera il risultato come tipo int. Per evitare questo problema bisogna dire al compilatore che deve trattare l’intera espressione come un long aggiungendo L al primo valore che viene valutato nell’espressione:
long secondi_in_un_giorno = 60L * 60 * 24;
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 05: Ordine di esecuzione operazioni matematiche in C
// Uso corretto del tipo long.
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo corretto del numero di secondi in un giorno:");
Serial.println("secondi_in_un_giorno = 60L * 60 * 24");
long secondi_in_un_giorno = 60L * 60 * 24;
Serial.print("Secondi in un giorno = ");
Serial.println(secondi_in_un_giorno);
Serial.println("Giusto! Abbiamo detto con la L che l'intera espressione è da trattate come un long.");
Serial.println("");
abilitaMessaggio = 1;
}
}
Attenzione sempre alle parentesi!
Se le utilizzate ad esempio come nell’esempio che segue farà andare in overflow il risultato:
long secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24);
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 06: Ordine di esecuzione operazioni matematiche in C
// L'uso non corretto delle parentesi fa andare in overflow il risultato.
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo errato somma 1 al numero di secondi in un giorno");
Serial.println("secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24)");
long secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24);
Serial.print("Secondi in un giorno + 1 = ");
Serial.println(secondi_in_un_giorno_piu_uno);
Serial.println("Sbagliato! Attenzione sempre alle parentesi!");
Serial.println("Se le utilizzate ad esempio come indicato farà andare in overflow il risultato");
abilitaMessaggio = 1;
}
}
mentre la seguente espressione non farà andare in overflow il calcolo:
long secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24);
// Prof. Michele Maffucci
// Data: 08.02.2020
// Esempio 07: Ordine di esecuzione operazioni matematiche in C
// L'ordine del calcolo viene stabilito dalle parentesi, in questo modo
// il calcolo non farà andare in overflow il risultato.
// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;
void setup() {
// inizializzazione della comunicazione seriale
Serial.begin(9600);
}
void loop() {
// consente di visualizzare sulla Serial Monitor
// una sola stampa delle stringa
if (abilitaMessaggio == 0) {
// ritardo che evita la doppia stampa del messaggio
delay(200);
Serial.println("Calcolo errato somma 1 al numero di secondi in un giorno");
Serial.println("secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24)");
long secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24);
Serial.print("Secondi in un giorno + 1 = ");
Serial.println(secondi_in_un_giorno_piu_uno);
Serial.println("Corretto! Il calcolo inizierà dalle parentesi tonde.");
Serial.println("E' stata aggiunta la L al primo operando tra le parentesi tonde.");
abilitaMessaggio = 1;
}
}
Buon Coding a tutti 🙂