Vorzeichenbehaftete und nicht vorzeichenbehaftete Nummern

17

Wie würde die ALU in einem Mikroprozessor zwischen einer mit Vorzeichen versehenen Zahl -7, die mit 1111 bezeichnet ist, und einer mit Vorzeichen versehenen Zahl 15, die ebenfalls mit 1111 bezeichnet ist, unterscheiden?

noorav
quelle
3
Siehe die Antwort der entsprechenden Frage: cs.stackexchange.com/a/30047/28999 . Vorzeichenbehaftete -7 wird übrigens nicht als 1111 dargestellt. Das ist -1. Dann zB 1111 - 0001 = 1110 sowohl im signierten als auch im nicht signierten Fall (-2 vs 14)
Albert Hendriks
2
@ AlbertHendriks Fairerweise verwenden einige ältere Computer eine "Vorzeichengrößen-Darstellung" (ein Vorzeichenbit und Größenbits), und wir verwenden diesen Stil immer noch für z. B. IEEE-Floats. Sie sind einfach unelegant und schwer zu bearbeiten im Vergleich zu Zweierkomplement. n1
Draconis
1
Der Hauptunterschied besteht darin, wie sich die Operatoren "größer als" / "kleiner als" verhalten und ob die Rechtsverschiebung mit dem höchsten Bit ausgefüllt wird. Wenn Sie tatsächlich multiplizieren und dividieren, ist das Ergebnis dasselbe.
Rob
2
@Rob Das ist nicht ganz richtig. Addition, Subtraktion und Multiplikation sind zwischen dem vorzeichenlosen und dem Zweierkomplement gleich - vorausgesetzt, Ihre Ein- und Ausgänge sind gleich groß. Division ist nicht dasselbe 6/2 ist 3, aber -2/2 ist -1. Und viele CPUs haben Multiplikationsbefehle, bei denen die beiden Eingänge die gleiche Größe haben, der Ausgang jedoch doppelt so groß ist. In diesem Fall sind auch die beiden Komplemente nicht gleich.
Kasperd

Antworten:

14

Die kurze und einfache Antwort lautet: Nein. Keine moderne Hauptprozessor-ISA funktioniert so, wie Sie denken.

Für die CPU ist es nur ein kleines Muster. Es liegt an Ihnen, dem Programmierer, den Überblick zu behalten, was dieses Bitmuster bedeutet.

Im Allgemeinen unterscheiden ISAs beim Speichern nicht zwischen verschiedenen Datentypen. (Ignorieren von Spezialregistern wie z. B. Floating-Registern in einer FPU.) Es ist nur ein bedeutungsloses Bitmuster für die CPU. ISAs verfügen jedoch über verschiedene Arten von Anweisungen, die das Bitmuster auf unterschiedliche Weise interpretieren können. Beispielsweise arithmetische Befehle wie MUL, DIV, ADD, SUBinterpretiert das Bitmuster als eine Art - Nummer, während logische Befehle wie AND, OR, XORinterpretiert sie als ein Array von booleans. Es ist also Aufgabe des Programmierers (oder des Autors des Interpreters oder Compilers, wenn Sie eine höhere Sprache verwenden), die richtigen Anweisungen auszuwählen.

Beispielsweise kann es durchaus separate Anweisungen für vorzeichenbehaftete und nicht vorzeichenbehaftete Nummern geben. Einige ISAs enthalten auch Anweisungen für die Arithmetik mit binär codierten Dezimalstellen.

Beachten Sie jedoch, dass ich oben "Modern Mainstream ISA" geschrieben habe. Es gibt in der Tat nicht-Mainstream- oder historische ISAs, die anders funktionieren. Beispielsweise unterscheiden sowohl die ursprüngliche 48-Bit-CISC-ISA des IBM AS / 400 als auch die aktuelle POWER-basierte 64-Bit-RISC-ISA des Systems, das jetzt IBM i heißt, zwischen Zeigern und anderen Werten. Zeiger sind immer mit Tags versehen und enthalten Typinformationen und Rechteverwaltung. Die CPU weiß, ob ein Wert ein Zeiger ist oder nicht, und nur der privilegierte i / OS-Kernel darf Zeiger frei manipulieren. Benutzeranwendungen können Zeiger, die sie besitzen, nur mithilfe einer kleinen Anzahl sicherer Anweisungen so bearbeiten, dass sie auf den Speicher verweisen, den sie besitzen.

Es gab auch einige historische ISA-Entwürfe, die zumindest eine begrenzte Form der Typenerkennung beinhalteten.

Jörg W. Mittag
quelle
Beachten Sie, dass der Java-Bytecode auch als ISA zählt. Und es interessiert sich so ziemlich für Datentypen ...
John Dvorak
Java-Bytecode zählt gewissermaßen als ISA, in dem Sinne, dass er in Silizium implementiert wurde. Eine solche Prüfung auf Basistypen wird jedoch vom Klassenladeprogramm durchgeführt, sodass die Typen zur Laufzeit meist ignoriert werden können. Und natürlich hat Java-Bytecode überhaupt keine vorzeichenlosen Typen.
Pseudonym
@Pseudonym: Nun, technisch gesehen , ist es nicht zu haben char, das ist ein 16-Bit - Typ ohne Vorzeichen. Natürlich gibt es in Java-Bytecode noch keine vorzeichenlosen arithmetischen Anweisungen, da alle charWerte intfür die Arithmetik automatisch auf (32-Bit- Vorzeichen ) hochgestuft werden.
Ilmari Karonen
42

Kurzfassung: Es weiß nicht. Man kann es nicht sagen.

Wenn 1111für -7 steht, haben Sie eine Darstellung der Vorzeichengröße, bei der das erste Bit das Vorzeichen und der Rest der Bits die Größe ist. In diesem Fall ist die Arithmetik etwas kompliziert, da ein vorzeichenloses Add und ein vorzeichenbehaftetes Add unterschiedliche Logik verwenden. Sie hätten also wahrscheinlich einen SADDund einen UADDOpcode, und wenn Sie den falschen auswählen, erhalten Sie unsinnige Ergebnisse.

In 1111der sogenannten Zweierkomplement-Repräsentation steht sie jedoch häufiger für -1 . In diesem Fall ist es der ALU einfach egal, ob die Nummern signiert oder nicht signiert sind! Nehmen wir zum Beispiel die Operation von 1110 + 0001. In der vorzeichenbehafteten Arithmetik bedeutet dies "-2 + 1" und das Ergebnis sollte -1 ( 1111) sein. In vorzeichenloser Arithmetik bedeutet dies "14 + 1" und das Ergebnis sollte 15 ( 1111) sein. Die ALU weiß also nicht, ob Sie ein signiertes oder ein nicht signiertes Ergebnis wünschen, und es ist ihr egal. Die Addition wird so ausgeführt, als wäre sie nicht signiert, und wenn Sie sie anschließend als vorzeichenbehaftete Ganzzahl behandeln möchten, liegt dies bei Ihnen.

EDIT: Wie Ruslan und Daniel Schepler in den Kommentaren zutreffend hervorheben, benötigen einige Operanden auch auf einem Zwei-Komponenten-Rechner noch getrennte Versionen mit und ohne Vorzeichen. Addition, Subtraktion, Multiplikation, Gleichheit usw. funktionieren einwandfrei, ohne zu wissen, ob die Zahlen signiert sind oder nicht. Divisions- und Über- / Unter-Vergleiche müssen jedoch separate Versionen haben.

BEARBEITEN BEARBEITEN : Es gibt auch einige andere Darstellungen, wie die eigene Ergänzung , aber diese werden im Grunde genommen nie mehr verwendet, sodass Sie sich keine Sorgen mehr machen sollten.

Draconis
quelle
Ah, gotcha. Danke dafür :)
noorav
10
In der Zweierkomplementdarstellung sind drei arithmetische Operationen vorzeichenunabhängig: Addition, Subtraktion und Multiplikation (mit Produkt gleicher Länge wie Operanden). Nur die Division muss für vorzeichenbehaftete Operanden unterschiedlich behandelt werden.
Ruslan
4
Es gibt auch einen Vergleich: < <= >= >sind für vs. unsigned Operanden unterzeichnet , während ==und !=sind Signedness unabhängig.
Daniel Schepler
Die Multiplikation hat häufig signierte und nicht signierte Sorten: 0xFFFFFFFF * 0xFFFFFFFF ist 0xFFFFFFFE00000001, wenn sie nicht signiert ist, und 0x0000000000000001, wenn sie signiert ist. Prozessoren wie Intel geben das Ergebnis in 2 Registern zurück, und das oberste Register unterscheidet sich für signierte und nicht signierte. Das unterste Register ist in beiden Situationen 1.
Rudy Velthuis
9

Einer der großen Vorteile der Zweierkomplement-Mathematik, die in allen modernen Architekturen verwendet wird, besteht darin, dass die Additions- und Subtraktionsanweisungen für vorzeichenbehaftete und vorzeichenlose Operanden genau gleich sind.

Viele CPUs haben nicht einmal Multiplikations-, Divisions- oder Modulusbefehle. Wenn dies der Fall ist, müssen die Anweisungen in getrennten, signierten und nicht signierten Formen vorliegen, und der Compiler (oder der Assembler-Programmierer) wählt die entsprechende aus.

CPUs haben im Allgemeinen auch unterschiedliche Anweisungen für vorzeichenbehaftete oder vorzeichenlose Vergleiche. Beispielsweise könnte x86 einem CMPmit JL(Jump if Less than) folgen, wenn der Vergleich signiert werden soll, oder JB(Jump if Below), wenn der Vergleich nicht signiert werden soll. Auch hier würde der Compiler oder der Programmierer die richtige Anweisung für den Datentyp auswählen.

Einige andere Anweisungen kommen häufig in vorzeichenbehafteten und vorzeichenlosen Varianten vor, z. B. das Verschieben nach rechts oder das Laden eines Werts in ein breiteres Register mit oder ohne Vorzeichenerweiterung.

Davislor
quelle
1
Sogar die Multiplikation ist für vorzeichenlose und vorzeichenbehaftete (Zweierkomplement) Ganzzahlen gleich, solange das Ergebnis nicht mehr Bits als die Eingaben enthalten muss . Wenn Sie eine Multiplikation mit 8 × 8 → 16 Bit (oder 16 × 16 → 32 Bit usw.) durchführen, müssen Sie die Eingaben (oder die Zwischenergebnisse) jedoch mit Vorzeichen erweitern .
Ilmari Karonen
@IlmariKaronen Das ist wahr; ARM A32 / A64 sind Befehlssätze, die viele Formen des Multiplikationsbefehls enthalten, einschließlich vorzeichenunabhängiger Multiplikationsaddition, die nur die Bits niedrigerer Ordnung schreibt, aber auch smulhund umulhdie nur die oberen Bits der Multiplikation und vorzeichenbehaftete und vorzeichenlose Befehle zurückgeben Liefert das Ergebnis in einem Register, das doppelt so breit ist wie die Quelloperanden.
Davislor
6

Das tut es nicht. Der Prozessor verwendet den Befehlssatz, um anzugeben, welche Art von Daten er betrachtet und wohin sie gesendet werden sollen. Im Operanden selbst gibt es nichts über Einsen und Nullen, was der ALU von Natur aus signalisieren könnte, ob es sich bei den Daten um Zeichen, Float, Int, Int mit Vorzeichen usw. handelt als 2s-Ergänzung zu interpretieren.

Jay Speidell
quelle
Auf charHardware-Ebene gibt es so etwas wie kein . Vielleicht war es einmal in der Zeit der mechanischen Ferndrucker. Aber heute, eine charist nur eine Zahl, soweit die Hardware betrifft. Der Grund, warum unterschiedliche Zahlen unterschiedlichen Buchstabenformen auf Ihrem Bildschirm entsprechen, ist, dass diese Zahlen verwendet werden, um unterschiedliche Bitmaps oder verschiedene Zeichenroutinen aus einer großen Tabelle (dh aus einer "Schriftart") auszuwählen.
Solomon Slow
3

Zu den bereits gemachten Antworten möchte ich noch etwas hinzufügen:

In den meisten anderen Antworten wird darauf hingewiesen, dass in der Zweierkomplementarithmetik das Ergebnis für vorzeichenbehaftete und vorzeichenlose Zahlen dasselbe ist:

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

Es gibt jedoch Ausnahmen:

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

(*) Bei vielen CPUs ist das Ergebnis einer Multiplikation von zwei n-Bit-Zahlen (2 * n) Bits breit.

Für solche Operationen haben die CPUs unterschiedliche Anweisungen für vorzeichenbehaftete und vorzeichenlose Arithmetik.

Dies bedeutet, dass der Programmierer (oder der Compiler) andere Anweisungen für vorzeichenbehaftete und vorzeichenlose Arithmetik verwenden muss.

Die x86-CPU hat zum Beispiel einen Befehl, der divfür das Ausführen einer vorzeichenlosen Division und einen Befehl, der idivfür das Ausführen einer vorzeichenbehafteten Division benannt ist.

Es gibt auch verschiedene "bedingte" Anweisungen (bedingte Sprünge, Bit-Ein-Bedingung setzen) sowie Multiplikationsanweisungen für vorzeichenbehaftete und vorzeichenlose Arithmetik.

Martin Rosenau
quelle