Numeri firmati e non firmati


17

In che modo l'ALU in un microprocessore distingue tra un numero con segno, -7 indicato con 1111 e un numero senza segno 15, indicato anche con 1111?


3
Vedere la risposta alla domanda correlata: cs.stackexchange.com/a/30047/28999 . A proposito, il segno -7 non è rappresentato come 1111. Quello è -1. Quindi ad es. 1111 - 0001 = 1110 sia nel caso firmato che non firmato (-2 vs 14)
Albert Hendriks

2
@AlbertHendriks In tutta onestà, alcuni computer più vecchi usano una "rappresentazione di magnitudo segno" (un bit di segno e bit di magnitudine), e usiamo ancora quello stile per es. Galleggianti IEEE. Sono semplicemente ineleganti e difficili da lavorare rispetto al complemento a due. n-1
Draconis

1
La differenza principale sta nel modo in cui si comportano gli operatori Maggiore / minore rispetto agli operatori e se lo spostamento a destra riempie con il bit più alto. Quando moltiplichi e dividi effettivamente, il risultato è lo stesso.
Rob


2
@Rob Non è del tutto corretto. Addizione, sottrazione e moltiplicazione sono tutte uguali tra unsigned e il complemento a due, supponendo che input e output abbiano le stesse dimensioni. La divisione non è la stessa 6/2 è 3, ma -2/2 è -1. E molte CPU hanno istruzioni di moltiplicazione in cui i due ingressi hanno dimensioni identiche, ma l'output ha dimensioni doppie, nel qual caso unsigned e il complemento a due non sono uguali.
Kasperd,

Risposte:


14

La risposta breve e semplice è: non lo è. Nessuna ISA CPU tradizionale moderna funziona come credi.

Per la CPU, è solo un po 'di modello. Spetta a te, il programmatore, tenere traccia di ciò che significa quel modello di bit.

In generale, gli ISA non distinguono tra diversi tipi di dati, quando si tratta di archiviazione. (Ignorando i registri per scopi speciali come i registri fluttuanti in una FPU.) È solo un modello insignificante di bit per la CPU. Tuttavia, ISA fare hanno diversi tipi di istruzioni che possono interpretare lo schema di bit in modi diversi. Ad esempio, le istruzioni aritmetiche come MUL, DIV, ADD, SUBinterpretano la sequenza di bit come una sorta di numero, mentre istruzioni logiche quali AND, OR, XORinterpretarlo come un array di booleani. Quindi, spetta al programmatore (o all'autore dell'interprete o del compilatore se si utilizza un linguaggio di livello superiore) scegliere le istruzioni corrette.

Ad esempio, potrebbero esserci istruzioni separate per numeri firmati e non firmati. Alcuni ISA hanno anche istruzioni per l'aritmetica con decimali con codice binario.

Tuttavia, nota che ho scritto "ISA mainstream moderno" sopra. Esistono infatti ISA non tradizionali o storici che funzionano in modo diverso. Ad esempio, sia l'ISA CISC originale a 48 bit dell'IBM AS / 400 che l'attuale ISA RISC a 64 bit basato sul POWER del sistema ora chiamato IBM i, distinguono tra puntatori e altri valori. I puntatori sono sempre taggati e includono informazioni sul tipo e gestione dei diritti. La CPU sa se un valore è o meno un puntatore e solo il kernel i / OS privilegiato può manipolare liberamente i puntatori. Le applicazioni utente possono solo manipolare i puntatori che possiedono per puntare alla memoria di loro proprietà usando un piccolo numero di istruzioni sicure.

C'erano anche alcuni progetti storici ISA che includevano almeno una forma limitata di consapevolezza del tipo.


Si noti che il bytecode Java conta anche come ISA. E praticamente importa dei tipi di dati ...
John Dvorak,

Il bytecode Java conta come un ISA, nel senso che è stato implementato in silicio. Tuttavia, il controllo del tipo di base di questo tipo è il controllo eseguito dal classloader, quindi i tipi possono essere ignorati principalmente in fase di esecuzione. E ovviamente il bytecode Java non ha tipi senza segno in primo luogo.
Pseudonimo del

@Pseudonym: Beh, tecnicamente, non ha char, che è un tipo senza segno a 16 bit. Naturalmente, non ci sono ancora istruzioni aritmetiche senza segno nel bytecode Java, poiché qualsiasi charvalore viene automaticamente promosso a int(con segno a 32 bit) per l'aritmetica.
Ilmari Karonen,

42

Versione breve: non lo sa. Non c'è modo di dirlo.

Se 1111rappresenta -7, allora hai una rappresentazione di magnitudine segno , dove il primo bit è il segno e il resto dei bit è la magnitudine. In questo caso, l'aritmetica è alquanto complicata, poiché un'aggiunta senza segno e un'aggiunta con segno usano una logica diversa. Quindi probabilmente avresti un SADDe un UADDcodice operativo, e se scegli quello sbagliato otterrai risultati insensati.

Più spesso, tuttavia, 1111rappresenta -1, in quella che viene chiamata rappresentazione del complemento a due . In questo caso, l'ALU semplicemente non si preoccupa se i numeri sono firmati o non firmati! Ad esempio, prendiamo l'operazione di 1110 + 0001. In aritmetica firmata, questo significa "-2 + 1" e il risultato dovrebbe essere -1 ( 1111). In aritmetica senza segno, questo significa "14 + 1" e il risultato dovrebbe essere 15 ( 1111). Quindi l'ALU non sa se si desidera un risultato con o senza segno e non gliene importa. Fa semplicemente l'aggiunta come se non fosse firmata, e se vuoi trattarla come un intero con segno in seguito, dipende da te.

EDIT: Come Ruslan e Daniel Schepler sottolineano giustamente nei commenti, alcuni operandi hanno ancora bisogno di versioni separate con segno e senza segno, anche su una macchina a due complementi. Addizione, sottrazione, moltiplicazione, uguaglianza e così via funzionano bene senza sapere se i numeri sono firmati o meno. Ma la divisione e ogni confronto maggiore o minore devono avere versioni separate.

MODIFICA MODIFICA: Ci sono anche altre rappresentazioni, come il complemento a una persona , ma queste non sono praticamente più utilizzate, quindi non dovresti preoccuparti di loro.


Ah, capito. Grazie per questo :)
noorav l'

10
Nella rappresentazione del complemento a due, tre operazioni aritmetiche sono indipendenti dalla firma: addizione, sottrazione e moltiplicazione (con prodotto della stessa lunghezza degli operandi). Solo la divisione deve essere gestita in modo diverso per gli operandi firmati.
Ruslan,

4
C'è anche un confronto: < <= >= >sono diversi per gli operandi con segno e non con segno mentre ==e !=sono indipendenti dalla firma.
Daniel Schepler,

La moltiplicazione ha spesso varietà firmate e non firmate: 0xFFFFFFFF * 0xFFFFFFFF è 0xFFFFFFFE00000001 se non firmato e 0x000000000000000001 se firmato. Processori come Intel restituiscono il risultato in 2 registri e il registro superiore differisce per i firmati e i non firmati. Il registro inferiore è 1 in entrambe le situazioni.
Rudy Velthuis,

9

Uno dei grandi vantaggi della matematica a due complementi, che usano tutte le architetture moderne, è che le istruzioni di addizione e sottrazione sono esattamente le stesse per operandi con o senza segno.

Molte CPU non hanno nemmeno istruzioni per la moltiplicazione, la divisione o il modulo. In tal caso, devono avere forme separate e non firmate dell'istruzione e il compilatore (o il programmatore del linguaggio assembly) sceglie quello appropriato.

Le CPU generalmente hanno anche istruzioni diverse per confronti con o senza segno. Ad esempio, x86 potrebbe seguire una CMPcon JL(Vai se inferiore) se il confronto deve essere firmato, oJB (Vai se al di sotto) se il confronto dovrebbe essere firmato. Ancora una volta, il compilatore o il programmatore sceglierebbe l'istruzione corretta per il tipo di dati.

Alcune altre istruzioni vengono spesso in varianti firmate e non firmate, come spostamento a destra o caricamento di un valore in un registro più ampio, con o senza estensione del segno.


1
Anche la moltiplicazione è la stessa per gli interi senza segno e con segno (complemento a due), purché non sia necessario che il risultato abbia più bit degli input . Se stai facendo qualcosa come la moltiplicazione 8 × 8 → 16 bit (o 16 × 16 → 32 bit, ecc.), Tuttavia, devi firmare estendere gli ingressi (o i risultati intermedi) .
Ilmari Karonen,

@IlmariKaronen Questo è vero; ARM A32 / A64 sono set di istruzioni che hanno molte forme di istruzione si moltiplicano, tra cui sign-agnostic multiply-add che scrive solo i bit di ordine inferiore, ma anche smulhe umulhche restituiscono solo i bit superiori della moltiplicazione e le istruzioni con e senza segno che restituisce il risultato in un registro due volte più largo degli operandi di origine.
Davislor,

6

Non Il processore si affida al set di istruzioni per dirgli quale tipo di dati sta guardando e dove inviarlo. Non c'è nulla circa 1 e 0 nell'operando stesso che può intrinsecamente segnalare all'ALU se i dati sono un carattere, float, int, firmato int, ecc. Se quell'1111 sta andando su un circuito elettrico che si aspetta un complemento 2s, sta andando da interpretare come un complemento 2s.


Non esiste una cosa chara livello hardware. Forse una volta, ai tempi delle teleprinter meccaniche. Ma oggi, a charè solo un numero per quanto riguarda l'hardware. Il motivo per cui numeri diversi corrispondono a forme diverse di lettere sullo schermo è che quei numeri vengono utilizzati per selezionare bitmap diverse o diverse routine di disegno da una grande tabella (cioè da un "carattere").
Solomon Slow

3

Vorrei aggiungere un'aggiunta alle risposte già fatte:

Nella maggior parte delle altre risposte si nota che nell'aritmetica a due complementi il ​​risultato è lo stesso per i numeri con e senza segno:

-2 + 1 = -1     1110 + 0001 = 1111
14 + 1 = 15     1110 + 0001 = 1111

Tuttavia , ci sono eccezioni:

Division:
  -2 / 2 = -1     1110 / 0010 = 1111
  14 / 2 = 7      1110 / 0010 = 0111
Comparison:
  -2 < 2 = TRUE   1110 < 0010 = TRUE
  14 < 2 = FALSE  1110 < 0010 = FALSE
"Typical" (*) multiplication:
  -2 * 2 = -4     1110 * 0010 = 11111100
  14 * 2 = 28     1110 * 0010 = 00011100

(*) Su molte CPU il risultato di una moltiplicazione di due numeri n-bit è largo (2 * n).

Per tali operazioni le CPU hanno istruzioni diverse per l'aritmetica firmata e non firmata.

Ciò significa che il programmatore (o il compilatore) deve utilizzare altre istruzioni per l'aritmetica firmata e non firmata.

La CPU x86 ad esempio ha un'istruzione chiamata divper fare una divisione senza segno e un'istruzione chiamata idivper fare una divisione firmata.

Esistono anche diverse istruzioni "condizionali" (salti condizionali, set-bit-on-condition) e istruzioni di moltiplicazione per l'aritmetica con o senza segno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.