value unsigned: 0 value signed: 0
value unsigned: 2046 value signed: 2046
value unsigned: 3545 value signed: 3545
value unsigned: 4094 value signed: 4094
value unsigned: 3548 value signed: 3548
value unsigned: 2052 value signed: 2052
value unsigned: 6 value signed: 6
value unsigned: 0 value signed: -2040
value unsigned: 0 value signed: -3542
value unsigned: 0 value signed: -4094
value unsigned: 0 value signed: -3551
value unsigned: 0 value signed: -2046
value unsigned: 0 value signed: 0
Assegnando un valore negativo ad un unsigned int mi sarei aspettato un qualcosa del tipo:
the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type)
Effettivamente i led si comportano in quel modo, rimanendo spenti. volevo capire come mai ottengo questo tipo di output.
giacomomae:
Assegnando un valore negativo ad un unsigned int mi sarei aspettato un qualcosa del tipo:
Il calcolo del seno rende un valore float, un float negativo è un valore che non può essere convertito tramite casting in unsigned int, questo tipo di operazione da sempre 0, mentre può essere convertito in signed int.
Solo se assegni ad un unsigned int il valore float negativo questo diventa il relativo complemento a due su 16 bit.
Questo semplice codice di test dimostra quanto esposto sopra:
float a;
unsigned int b;
void setup() {
Serial.begin(19200);
a = 55,12;
Serial.println ((unsigned int)a);
Serial.println ((int)a);
a = -55,12;
Serial.println ((unsigned int)a);
Serial.println ((int)a);
b = a;
Serial.println (b);
}
void loop() {
}
astrobeed:
Il calcolo del seno rende un valore float, un float negativo è un valore che non può essere convertito tramite casting in unsigned int, questo tipo di operazione da sempre 0, mentre può essere convertito in signed int.
Solo se assegni ad un unsigned int il valore float negativo questo diventa il relativo complemento a due su 16 bit.
Grazie per la risposta!
Mi hai dato un ottimo spunto di riflessione :
mi sono andato a rileggere il K&R (non ci si impara mai abbastanza)
in appendice A.6.2 conversioni integrali ho trovato (quello che mi sarei aspettato io ):
Un intero è convertito in un dato tipo senza segno individuando il più piccolo valore non negativo che sia congruo a quell'intero Modulo (MAX_VALUE+1)
ovvero quello che avviene nel tuo programmino quando fai
b = a
cioè fai una conversione float -> signed int -> unsigned int
pero' poco più sotto in A.6.3 si svela l'arcano! :
ciò che risulta dalla conversione di valori in virgola mobile negativi in tipi integrali privi di segno non è specificato
quindi la conversione negative float -> unsigned int
dipende dall'implementazione del compilatore!
zoomx:
Vorrei capire che cosa vi aspettavate dalla conversione di un numero negativo in uno senza segno.
In binario i numeri negativi sono rappresentati come 2^n - valore, ove n è il numero di bit significativi, se ragioniamo su otto bit -1 è pari a 2^8-1 = 256 - 1 = 255, il limite è dato dall'ultimo bit della word, se è ZERO il numero è positivo, se è UNO il numero è negativo.
Se assegni, o fai il cast, un numero negativo su una variabile di tipo unsigned ottieni il suo valore assoluto senza segno, pertanto -1 diventa 255 se sono unsigned char, 65535 se sono unsigned int.
astrobeed:
Se assegni, o fai il cast, un numero negativo su una variabile di tipo unsigned ottieni il suo valore assoluto senza segno, pertanto -1 diventa 255 se sono unsigned char, 65535 se sono unsigned int.
La mia domanda era cosa ci si aspetta dal punto di vista logico.
Secondo quanto scritto sopra
ciò che risulta dalla conversione di valori in virgola mobile negativi in tipi integrali privi di segno non è specificato
quindi usare il cast da risultati imprevedibili, nel senso che dipendono dal compilatore. Ma io chiedevo perché usare il cast, che a quanto pare da risultati imprevedibili, quando ci sono funzioni apposta che invece hanno un risultato identico (in ogni compilatore), tipo quelle che restituiscono il valore assoluto e la parte intera.
zoomx:
La mia domanda era cosa ci si aspetta dal punto di vista logico.
Secondo quanto scritto sopra
La tua domanda non ha alcun senso, i casi sono due o conosci la matematica binaria e il linguaggio, quindi sai cosa aspettarti, oppure non lo conosci e non sai cosa aspettarti, nel secondo caso basta studiare.
In tutti i casi il casting di un float negativo verso un valore unsigned produce sempre 0, è previsto esplicitamente nel C ANSI, il motivo è legato alla natura esponenziale dei float e per come vengono rappresentati in memoria, oltretutto non esiste un solo formato per i float.
astrobeed:
In tutti i casi il casting di un float negativo verso un valore unsigned produce sempre 0, è previsto esplicitamente nel C ANSI
sul kernigan, come già riportato precedentemente, ho trovato scritto (Par. A.6.3):
ciò che risulta dalla conversione di valori in virgola mobile negativi in tipi integrali privi di segno non è specificato
che mi sembra non sia perfettamente allineato con quello che stai dicendo,
mi potresti dare dei chiarimenti in merito?
quindi usare il cast da risultati imprevedibili, nel senso che dipendono dal compilatore.
no no i risultati sono prevedibilissimi.
E' la stessa cosa che succede utilizzando una arduino DUE o una UNO:
per l'arduino due un int è un'intero a 32 bit,
mentre per la UNO un int è a 16 bit
ma non è che se fai 65535 * 2 il risultato è imprevedibile.
con la due hai come risultato 131070
con la uno -2
Poco sopra quoti il K&R secondo cui ciò che risulta dalla conversione di valori in virgola mobile negativi in tipi integrali privi di segno non è specificato. Poi però più sotto scrivi che il risultato è prevedibilissimo.
Forse diamo un significato diverso alle parole "non è specificato".
su una UNO è -2 e non -1. Appena provato. Ho anche scoperto che l'emulatore di Codeblock invece stampa 131070 segno che gli interi non occupano 2 byte, come sulla UNO che deve emulare, ma 4.
Astrobeed,
la mia tesi è che il casting di un numero negativo in un unsigned non è un'operazione intelligente, ma forse mi sbaglio.
zoomx:
Poco sopra quoti il K&R secondo cui ciò che risulta dalla conversione di valori in virgola mobile negativi in tipi integrali privi di segno non è specificato. Poi però più sotto scrivi che il risultato è prevedibilissimo.
Forse diamo un significato diverso alle parole "non è specificato".
su una UNO è -2 e non -1. Appena provato. Ho anche scoperto che l'emulatore di Codeblock invece stampa 131070 segno che gli interi non occupano 2 byte, come sulla UNO che deve emulare, ma 4.
Astrobeed,
la mia tesi è che il casting di un numero negativo in un unsigned non è un'operazione intelligente, ma forse mi sbaglio.
si si il risultato è -2
ho sbagliato a digitare! chiedo venia!
prevedibile una volta fissato il compilatore!
e infatti ho previsto l risultato sia per la uno che per la due
giacomomae:
sul kernigan, come già riportato precedentemente, ho trovato scritto (Par. A.6.3):
Il K&R è un testo obsoleto, devi fare riferimento al C standard che tutti i compilatori implementano, ovvero il C ANSI, come minimo il C99 (stabilito nel 2000) ISO/IEC 9899:1999.
Lasciamo perdere i compilatori non ANSI C o dialetti vari del C, quelli non li prendo nemmeno in considerazione in quanto i problemi sono ben altri.
zoomx:
la mia tesi è che il casting di un numero negativo in un unsigned non è un'operazione intelligente, ma forse mi sbaglio.
Dipende da cosa devi fare, il casting è uno strumento comodo e potente, come i puntatori, però tocca saperlo usare altrimenti si va incontro a casini inenarrabili
viene compilato senza problemi (IDE 1.0.6) e che il risultato della divisione per zero è uno. Codeblock invece mi da un warning (warning: division by zero [-Wdiv-by-zero]) e l'emulatore va in crash. A quanto ho capito il C non prevede affatto controlli del genere. Invece è pignolo per i punti e virgola mancanti (o è il preprocessore?).
La divisione esplicita per zero è ovviamente una operazione cretina.
zoomx:
viene compilato senza problemi (IDE 1.0.6) e che il risultato della divisione per zero è uno. Codeblock invece mi da un warning (warning: division by zero [-Wdiv-by-zero]) e l'emulatore va in crash. A quanto ho capito il C non prevede affatto controlli del genere. Invece è pignolo per i punti e virgola mancanti (o è il preprocessore?).
E' l'ide di Arduino che non ti fa vedere i warning, setta un livello molto basso, il C lo da eccome il warning per la divisione per zero, se poi fai girare il programma il crash è garantito, se provi a compilare con Atmel Studio e avr-gcc le vedi tutte le warning.
Figurati che nei micro di livello superiore, p.e. i dsPIC senza dover arrivare agli ARM, il compilatore C prevede degli appositi interrupt di trap nel caso si verificano condizioni critiche di errore a run time, tra cui il divide by zero.