Giusto spostando i numeri negativi in ​​C

Ho il codice C in cui faccio quanto segue.

int nPosVal = +0xFFFF; // + Added for ease of understanding int nNegVal = -0xFFFF; // - Added for valid reason 

Ora quando ci provo

 printf ("%d %d", nPosVal >> 1, nNegVal >> 1); 

ottengo

 32767 -32768 

È previsto?

Sono in grado di pensare qualcosa di simile

 65535 >> 1 = (int) 32767.5 = 32767 -65535 >> 1 = (int) -32767.5 = -32768 

Cioè, -32767.5 è arrotondato a -32768.

Questa comprensione è corretta?

Sembra che la tua implementazione stia probabilmente facendo uno spostamento di bit aritmetico con i numeri di complemento di due. In questo sistema, sposta tutti i bit a destra e quindi riempie i bit superiori con una copia di qualunque fosse l’ultimo bit. Quindi, per il tuo esempio, trattando int come 32-bit qui:

 nPosVal = 00000000000000001111111111111111 nNegVal = 11111111111111110000000000000001 

Dopo il turno, hai:

 nPosVal = 00000000000000000111111111111111 nNegVal = 11111111111111111000000000000000 

Se si converte questo valore in decimale, si ottengono rispettivamente 32767 e -32768.

In effetti, uno spostamento verso destra va verso l’infinito negativo.

Modifica: in base alla Sezione 6.5.7 dell’ultima bozza di norma , questo comportamento sui numeri negativi dipende dall’implementazione:

Il risultato di E1 >> E2 è E1 con posizioni di bit E2 spostate a destra. Se E1 ha un tipo senza segno o se E1 ha un tipo firmato e un valore non negativo, il valore del risultato è la parte integrante del quoziente di E1 / 2 E2 . Se E1 ha un tipo firmato e un valore negativo, il valore risultante è definito dall’implementazione.

Il loro razionale dichiarato per questo:

Il Comitato C89 ha affermato che la libertà di implementazione concessa da K & R non richiede che l’operazione di spostamento a destra firmata sia firmata in estensione, dal momento che un tale requisito potrebbe rallentare il codice veloce e poiché l’utilità del prolungamento del segno è marginale. (Spostando aritmeticamente a destra un complemento a due di un numero intero negativo, un posto non equivale a dividere per due!)

Quindi la sua implementazione dipende dalla teoria. In pratica, non ho mai visto un’implementazione non effettuare uno spostamento aritmetico proprio quando è firmato l’operando di sinistra.

No, non si ottengono numeri frazionari come 0.5 quando si lavora con numeri interi. I risultati possono essere facilmente spiegati quando si guardano le rappresentazioni binarie dei due numeri:

  65535: 00000000000000001111111111111111 -65535: 11111111111111110000000000000001 

Bit che si sposta a destra di un bit e si estende a sinistra (nota che questo dipende dall’implementazione, grazie a Trent):

  65535 >> 1: 00000000000000000111111111111111 -65535 >> 1: 11111111111111111000000000000000 

Converti di nuovo in decimale:

  65535 >> 1 = 32767 -65535 >> 1 = -32768 

La specifica C non specifica se il bit del segno è spostato o meno. È dipendente dall’implementazione.

Quando si sposta a destra, il bit meno significativo viene scartato.

0xFFFF = 0 1111 1111 1111 1111, che sposta a destra per dare 0 0111 1111 1111 1111 = 0x7FFF

-0xFFFF = 1 0000 0000 0000 0001 (complemento 2 secondi), che passa a destra per 1 1000 0000 0000 0000 = -0x8000

A-1: Sì. 0xffff >> 1 è 0x7fff o 32767. Non sono sicuro di cosa fa -0xffff. È strano

A-2: lo spostamento non è la stessa cosa della divisione. È un bit shifting, un’operazione binaria primitiva. Che a volte può essere utilizzato per alcuni tipi di divisione è conveniente, ma non sempre lo stesso.

Al di sotto del livello C, le macchine hanno un core CPU che è interamente intero o scalare . Sebbene in questi giorni ogni CPU desktop abbia una FPU, questo non è sempre stato il caso e anche oggi i sistemi embedded sono realizzati senza istruzioni in virgola mobile.

I paradigmi di programmazione di oggi, i design e le lingue della CPU risalgono all’era in cui la FPU potrebbe non esistere nemmeno.

Quindi, le istruzioni della CPU implementano operazioni a punti fissi , generalmente trattate come operazioni puramente intere . Solo se un programma dichiara elementi di float o double , esistono frazioni. (Bene, puoi usare le CPU ops per “punto fisso” con le frazioni ma questo è ora e sempre piuttosto raro.)

Indipendentemente da quanto richiesto da un comitato standard di lingua anni fa, tutte le macchine ragionevoli propagano il bit del segno sui giusti spostamenti dei numeri firmati. I cambiamenti a destra dei valori senza segno si spostano sugli zeri a sinistra. I pezzi spostati a destra sono lasciati cadere sul pavimento.

Per approfondire la tua comprensione dovrai indagare su “aritmetica dei due complementi”.