Offline
Newbie
Karma: 0
Posts: 33
|
 |
« on: September 26, 2011, 11:52:35 am » |
Tie', beccatevi sto codice e provate cosa succede: /* Test by Ugo 26/09/2011 */ unsigned long goo=60;
void setup() { Serial.begin(57600); Serial.println("\nVediamo che succede\n"); for(int i=0; i<20; i++) { Serial.print( foo() ); Serial.println("<-"); };
Serial.end(); }
void loop() { }
unsigned long foo() { static int a; static int b = 5; static int c = 9; static unsigned long d; a = int(goo++); Serial.print("->"); Serial.print( a ); Serial.print("<->"); d = c*3600+ b*60 +a; return( d ) ; }
Ci ho perso tutto il w.e. per isolare sto tratto di codice per capire dove s'impallava il programma: ]  Bye, Ugo
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 83
Posts: 8239
:(){:|:&};:
|
 |
« Reply #1 on: September 26, 2011, 12:32:22 pm » |
un bug nelle tue conoscenze, trattasi di semplice overflow delle variabili int...  maggiori info: http://arduino.cc/en/Reference/Int
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 33
|
 |
« Reply #2 on: September 26, 2011, 12:38:56 pm » |
Stavolta non sono d'accordo. Qualsaisi compilatore serio alloca spazio per la variabile di destinazione, dove va a mettere i risultati, non viceversa. So' niubbo d'arduino, ma compilavo in C in tempi che sicuro te non eri ancora nato ;-) Bye, Ugo
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 83
Posts: 8239
:(){:|:&};:
|
 |
« Reply #3 on: September 26, 2011, 12:50:29 pm » |
ma stai scherzando? TUTTI i linguaggi che conosco soffrono di overflow di variabile! trovamene uno che non abbia questo problema, non dico che sia impossibile ma molto, molto difficile.
Altrimenti mi spieghi che differenza c'è tra dichiarare un int o un long o un byte?
e tra un float e un double?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 33
|
 |
« Reply #4 on: September 26, 2011, 01:03:38 pm » |
ma stai scherzando? TUTTI i linguaggi che conosco soffrono di overflow di variabile! trovamene uno che non abbia questo problema, non dico che sia impossibile ma molto, molto difficile.
Altrimenti mi spieghi che differenza c'è tra dichiarare un int o un long o un byte?
e tra un float e un double?
No, no, aspetta, non fraintendere. Un conto e' l'overflow e un conto e' l'allocazione di memoria. In tutti i compilatori che ho usato, tanti, ma mille anni fa, il problema che ho riscontrato qui non esisteva. E spiego meglio: Se alloco byte a; e poi ci vado a mettere dentro a=300; Ovvio che vado fuori, in overflow. se alloco byte a; int b = 300; va bene, ovviamente. e' evidente che se scrivo questo: byte a; int b; ... b= int(300); Va ancora bene ma e' une ridondanza inutile, visto che in "b" ho allocato il giusto spazio e "a" e' allocata Da qui, e' evidente che byte a; int b; ... b= 300*a; dovrebbe essere giusto. Ho capito che il compilatore di arduino non lo fa, pero' a questo punto si comporta in modo diverso Perche' se e' giusto b = int(300*a); Allora DEVE essere NECESSARIO e non opzionale anche b=int(a); Cia'
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 83
Posts: 8239
:(){:|:&};:
|
 |
« Reply #5 on: September 26, 2011, 01:09:24 pm » |
ah, ok, ora ho capito quello che intendi, ma sia il C, che il C++, che java, che php che python.... e posso ancora andare avanti... non ragionano così.
d = c*3600+ b*60 +a;
vuol dire: prendi C (che è int) e moltiplicalo con 3600 (sempre int), il risultato sarà messo in un int, essendo int la variabile "più grossa" (fregandosene bellamente dell'overflow), etc... alla fine il risultato verrà convertito in un long
puoi forzare, per esempio, 3600 ad esere long scrivendo 3600L
quindi d = c*3600+ b*60 +a; vuol dire: prendi C (che è int) e moltiplicalo con 3600 (ora è long), il risultato sarà messo in un long, essendo long la variabile "più grossa" (fregandosene bellamente di eventuali overflow), etc.
|
|
|
|
|
Logged
|
|
|
|
|
BZ (I)
Offline
Brattain Member
Karma: 162
Posts: 15742
+39 349 2158303
|
 |
« Reply #6 on: September 26, 2011, 01:35:48 pm » |
lelle persa
d = c*3600L+ b*60 +a;
Ciao Uwe
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 589
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #7 on: September 26, 2011, 04:38:56 pm » |
ah, ok, ora ho capito quello che intendi, ma sia il C, che il C++, che java, che php che python.... e posso ancora andare avanti... non ragionano così.
d = c*3600+ b*60 +a;
vuol dire: prendi C (che è int) e moltiplicalo con 3600 (sempre int), il risultato sarà messo in un int, essendo int la variabile "più grossa" (fregandosene bellamente dell'overflow), etc... alla fine il risultato verrà convertito in un long
puoi forzare, per esempio, 3600 ad esere long scrivendo 3600L
quindi d = c*3600+ b*60 +a; vuol dire: prendi C (che è int) e moltiplicalo con 3600 (ora è long), il risultato sarà messo in un long, essendo long la variabile "più grossa" (fregandosene bellamente di eventuali overflow), etc.
Buono a sapersi, non ci avevo mai pensato..... Sono quelle cose che ti fanno perdere ore di lavoro per una cavolata...
|
|
|
|
|
Logged
|
|
|
|
|
Forum Moderator
Italy
Offline
Brattain Member
Karma: 219
Posts: 16495
Don't know what I do
|
 |
« Reply #8 on: September 26, 2011, 04:47:52 pm » |
E' la conversione implicita dei tipi di dato. I calcoli vengono eseguiti usando il tipo di dati più grande tra quelli dell'operazione, ma il risultato viene poi riconvertito nel tipo di dati della variabile di destinazione. Provate questo sketch: void setup() { delay(2000); Serial.begin(19200); }
void loop() { byte a; a=1500*3500; Serial.println(a, DEC); delay(2000); } Sul terminale seriale apparirà scritto 208. Nessun errore da parte del compilatore, nessun comportamento strano da parte del micro. Semplicemente, del risultato vengono presi i primi 8 bit, quelli cioè che stanno in un tipo di dati byte, nonostante i calcoli siano eseguiti a 32 bit.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 589
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #9 on: September 26, 2011, 05:01:48 pm » |
Si, questo lo so, ma cosa succede se fai questo? void setup() { delay(2000); Serial.begin(19200); }
void loop() { byte a = 200; int b; b=a*10; Serial.println(b, DEC); delay(2000); } A quello che ho capito l'operazione a * 10 viene eseguita a 8 bit, generando un overflow, e il risultato (sbagliato) viene messo in un int, giusto? Purtroppo ora non ho arduino per provare...
|
|
|
|
|
Logged
|
|
|
|
|
Forum Moderator
Italy
Offline
Brattain Member
Karma: 219
Posts: 16495
Don't know what I do
|
 |
« Reply #10 on: September 26, 2011, 05:07:39 pm » |
No, ottieni 2000. Questo perché, come ti ho scritto, il compilatore fa sì che l'operazione venga eseguita usando il tipo di dati più grande necessario a contenere i valori in gioco e solo alla fine viene convertito il risultato per il tipo di dato in uso. Ora, siccome 200*10 va oltre il tipo byte, il compilatore fa usare un int (16 bit), ottieni così 2000 che viene memorizzato in una variabile di tipo int. Siccome int in un int ci sta, non hai nessun "pezzo" perso per la strada.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 589
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #11 on: September 26, 2011, 05:38:59 pm » |
No, ottieni 2000. Questo perché, come ti ho scritto, il compilatore fa sì che l'operazione venga eseguita usando il tipo di dati più grande necessario a contenere i valori in gioco e solo alla fine viene convertito il risultato per il tipo di dato in uso. Ora, siccome 200*10 va oltre il tipo byte, il compilatore fa usare un int (16 bit), ottieni così 2000 che viene memorizzato in una variabile di tipo int. Siccome int in un int ci sta, non hai nessun "pezzo" perso per la strada.
ah, ok, ora ho capito quello che intendi, ma sia il C, che il C++, che java, che php che python.... e posso ancora andare avanti... non ragionano così.
d = c*3600+ b*60 +a;
vuol dire: prendi C (che è int) e moltiplicalo con 3600 (sempre int), il risultato sarà messo in un int, essendo int la variabile "più grossa" (fregandosene bellamente dell'overflow), etc... alla fine il risultato verrà convertito in un long
puoi forzare, per esempio, 3600 ad esere long scrivendo 3600L
quindi d = c*3600+ b*60 +a; vuol dire: prendi C (che è int) e moltiplicalo con 3600 (ora è long), il risultato sarà messo in un long, essendo long la variabile "più grossa" (fregandosene bellamente di eventuali overflow), etc.
Chi ha ragione?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 83
Posts: 8239
:(){:|:&};:
|
 |
« Reply #12 on: September 26, 2011, 05:42:43 pm » |
No, ottieni 2000. Questo perché, come ti ho scritto, il compilatore fa sì che l'operazione venga eseguita usando il tipo di dati più grande necessario a contenere i valori in gioco e solo alla fine viene convertito il risultato per il tipo di dato in uso. Ora, siccome 200*10 va oltre il tipo byte, il compilatore fa usare un int (16 bit), ottieni così 2000 che viene memorizzato in una variabile di tipo int. Siccome int in un int ci sta, non hai nessun "pezzo" perso per la strada.
no. concordo sul risultato ma non sul motivo. scrivere "a*10" da per implicito che 10 sia un int, quindi: int b=a*10; sarà 2000 se fai a = a*10; l'operazione darà 2000 (perchè 10 è un int), ma poi verrà troncata in byte prova a fare uno skect di esempio: 2000 trocanto in byte credo sia 0 (caso a = a*10;) se invece fai byte b=10; byte a=200; a=a*b; //in modo che entrambi i membri siano forzatatmente in binario dovresti trovare un risultato diverso, credo (dovrei fare i conti)
|
|
|
|
|
Logged
|
|
|
|
|
Forum Moderator
Italy
Offline
Brattain Member
Karma: 219
Posts: 16495
Don't know what I do
|
 |
« Reply #13 on: September 26, 2011, 05:48:18 pm » |
Io  No, diciamo tutti e due, lesto non ha spiegato tutto. Prova questo codice: void setup() { delay(2000); Serial.begin(19200); }
void loop() { byte a; a=15000*35000; Serial.println(a, DEC); delay(2000); } 15000*35000=525000000, che è un numero a 28 bit. Eppure il terminale stampa ancora un valore coretto. 64 Che è appunto 525000000&255 (ossia i primi 8 bit) del numero. Se invece provi con a=150000*350000; otterrai 0. questo perché il risultato non può essere contenuto in 32 bit, il tipo di dati più grandi gestibile dall'Atmega e va in overflow, dando come risultato 0. Quindi l'overflow viene ignorato (o per meglio dire non si verifica) solo finché il risultato è contenibile in un dato gestibile dal micro.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 83
Posts: 8239
:(){:|:&};:
|
 |
« Reply #14 on: September 26, 2011, 06:12:51 pm » |
attento a scrivere a=15000*35000; non vorrei che il precompilatore ci metta le mani. Prova a mettere il 15000 e/o il 35000 in variabili int. Anzi il 35000 non ci sta in un int, quindi (sempre il precompilatore) potrebbe aggiungere una bella L o una unsigned di soppiatto! 15000*35000=525000000, che è un numero a 28 bit. Eppure il terminale stampa ancora un valore coretto. 64 Che è appunto 525000000&255 (ossia i primi 8 bit) del numero. se così fosse, ovvero avviene un cast implicito a long, allora ho sbagliato io. Ma non mi spiegherei più perchè il suo programma dà l'verflow a 32000 circa, il limte degli int (vedi sopra la mia possibile spiegazione) Se invece provi con a=150000*350000; otterrai 0. questo è quello che mi aspetterei di vedere (credo, non ho fatto i conti, e arduino è al momento impegnato)
|
|
|
|
|
Logged
|
|
|
|
|
|