Avere uno sfondo di matematica pura, questa è una presa leggermente più matematica per chiunque sia interessato.
Se iniziamo con un intero con segno e senza segno a 8 bit, ciò che abbiamo è fondamentalmente l'intero modulo 256, per quanto riguarda l'addizione e la moltiplicazione, a patto che il complemento a 2 sia usato per rappresentare interi negativi (ed è così che ogni processore moderno lo fa).
Dove le cose differiscono si trova in due punti: uno è operazioni di confronto. In un certo senso, gli interi modulo 256 sono meglio considerati una cerchia di numeri (come gli interi modulo 12 do su un quadrante analogico vecchio stile). Per rendere significativi i confronti numerici (è x < y), dovevamo decidere quali numeri sono meno di altri. Dal punto di vista del matematico, vogliamo incorporare gli interi modulo 256 nell'insieme di tutti gli interi in qualche modo. Mappare il numero intero a 8 bit la cui rappresentazione binaria è tutti zero per l'intero 0 è la cosa ovvia da fare. Possiamo quindi procedere alla mappatura degli altri in modo che '0 + 1' (il risultato dell'azzeramento di un registro, diciamo ax e dell'incremento di uno, tramite 'inc ax') vada al numero intero 1, e così via. Possiamo fare lo stesso con -1, ad esempio mappando '0-1' al numero intero -1, e '0-1-1' all'intero -2. Dobbiamo assicurarci che questa incorporazione sia una funzione, quindi non possiamo mappare un singolo intero da 8 bit a due interi. Come tale, questo significa che se mappiamo tutti i numeri nel set di numeri interi, ci sarà 0, insieme ad alcuni numeri interi minori di 0 e alcuni più di 0. Ci sono essenzialmente 255 modi per farlo con un intero a 8 bit (secondo a quale minimo si desidera, da 0 a -255). Quindi puoi definire 'x < in termini di '0 < y - x '.
Ci sono due casi d'uso comuni, per i quali il supporto hardware è ragionevole: uno con tutti i numeri interi diversi da zero e uno con uno spacco approssimativamente 50/50 attorno a 0. Tutte le altre possibilità sono facilmente emulate traducendo i numeri tramite un extra 'add e sub' prima delle operazioni, e la necessità di questo è così rara che non riesco a pensare ad un esempio esplicito nel software moderno (dal momento che puoi semplicemente lavorare con una mantissa più grande, diciamo 16 bit).
L'altro problema è quello di mappare un intero a 8 bit nello spazio degli interi a 16 bit. -1 va a -1? Questo è ciò che vuoi se 0xFF è pensato per rappresentare -1. In questo caso, estendere il segno è la cosa giusta da fare, in modo che 0xFF vada a 0xFFFF. D'altra parte, se 0xFF era pensato per rappresentare 255, allora lo si vuole mappare a 255, quindi a 0x00FF, piuttosto che a 0xFFFF.
Questa è la differenza tra le operazioni "shift" e "arithmetic shift".
In definitiva, tuttavia, si riduce al fatto che i file int nel software non sono interi, ma rappresentazioni in binario, e solo alcuni possono essere rappresentati. Quando si progetta l'hardware, è necessario fare delle scelte su cosa fare in modo nativo nell'hardware. Poiché con il complemento a 2 le operazioni di addizione e moltiplicazione sono identiche, ha senso rappresentare gli interi negativi in questo modo. Quindi è solo una questione di operazioni che dipendono da quali numeri interi le rappresentazioni binarie intendono rappresentare.