Pages: [1] 2   Go Down
Author Topic: Un bug del compilatore?  (Read 897 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tie', beccatevi sto codice e provate cosa succede:

Quote
/*
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:
 smiley-evil

Bye,
Ugo
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

un bug nelle tue conoscenze, trattasi di semplice overflow delle variabili int...  smiley-mr-green

maggiori info:
http://arduino.cc/en/Reference/Int
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

un bug nelle tue conoscenze, trattasi di semplice overflow delle variabili int...  smiley-mr-green

maggiori info:
http://arduino.cc/en/Reference/Int

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 Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

BZ (I)
Offline Offline
Brattain Member
*****
Karma: 251
Posts: 21254
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

lelle persa

d = c*3600L+ b*60 +a;

Ciao Uwe
Logged

Ivrea
Offline Offline
God Member
*****
Karma: 5
Posts: 680
"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
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Code:
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


Ivrea
Offline Offline
God Member
*****
Karma: 5
Posts: 680
"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
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Si, questo lo so, ma cosa succede se fai questo?

Code:
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

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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


Ivrea
Offline Offline
God Member
*****
Karma: 5
Posts: 680
"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
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Io  smiley-yell
No, diciamo tutti e due, lesto non ha spiegato tutto.

Prova questo codice:
Code:
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 Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

attento a scrivere
Code:
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!

Quote
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)

Quote
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

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Pages: [1] 2   Go Up
Jump to: