Avere un background matematico puro, 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 gli interi modulo 256, per quanto riguarda l'addizione e la moltiplicazione, a condizione che il complemento di 2 sia usato per rappresentare numeri interi negativi (ed è così che fa ogni processore moderno) .
Dove le cose differiscono è in due posti: uno sono le operazioni di confronto. In un certo senso, gli interi modulo 256 sono meglio considerati un cerchio di numeri (come gli interi modulo 12 fanno su un quadrante analogico vecchio stile). Per rendere significativi i confronti numerici (è x <y), è necessario decidere quali numeri sono inferiori rispetto ad altri. Dal punto di vista del matematico, vogliamo in qualche modo incorporare gli interi modulo 256 nell'insieme di tutti gli interi. Mappare l'intero a 8 bit la cui rappresentazione binaria è tutti zeri sull'intero 0 è la cosa ovvia da fare. Possiamo quindi procedere a mappare gli altri in modo che '0 + 1' (il risultato dell'azzeramento di un registro, ad esempio ax, e l'incremento di uno, tramite 'inc ax') vada all'intero 1 e così via. Possiamo fare lo stesso con -1, ad esempio mappando '0-1' sull'intero -1 e '0-1-1' all'intero -2. Dobbiamo garantire che questo incorporamento sia una funzione, quindi non è possibile mappare un singolo numero intero a 8 bit su due numeri interi. In quanto tale, ciò significa che se mappiamo tutti i numeri nell'insieme di numeri interi, 0 sarà lì, insieme ad alcuni numeri inferiori a 0 e alcuni più di 0. Esistono essenzialmente 255 modi per farlo con un numero intero a 8 bit (secondo al minimo desiderato, da 0 a -255). Quindi puoi definire 'x <y' in termini di '0 <y - x'.
Esistono due casi d'uso comuni, per i quali è ragionevole il supporto hardware: uno con tutti i numeri interi diversi da zero che è maggiore di 0 e uno con una divisione di circa 50/50 attorno a 0. Tutte le altre possibilità sono facilmente emulabili traducendo i numeri tramite un 'aggiunta aggiuntiva e sub "prima delle operazioni, e la necessità di questo è così rara che non riesco a pensare a 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 numero intero a 8 bit nello spazio di numeri interi a 16 bit. -1 va a -1? Questo è quello che vuoi se 0xFF deve rappresentare -1. In questo caso, l'estensione dei segni è la cosa ragionevole da fare, in modo che 0xFF vada a 0xFFFF. D'altra parte, se 0xFF doveva rappresentare 255, lo si desidera mappare a 255, quindi a 0x00FF, anziché a 0xFFFF.
Questa è la differenza tra le operazioni 'shift' e 'shift aritmetico'.
Alla fine, tuttavia, si riduce al fatto che gli int nel software non sono numeri interi, ma rappresentazioni in binario e solo alcuni possono essere rappresentati. Quando si progetta 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 numeri negativi in questo modo. Quindi è solo una questione di operazioni che dipendono da quali numeri interi rappresentino le tue rappresentazioni binarie.