Vorzeichenbehaftete oder vorzeichenlose Ganzzahlen

395

Bin ich richtig zu sagen, dass der Unterschied zwischen einer vorzeichenbehafteten und einer vorzeichenlosen Ganzzahl ist:

  1. Unsigned kann einen größeren positiven Wert und keinen negativen Wert enthalten.
  2. Unsigned verwendet das führende Bit als Teil des Werts, während die signierte Version das Bit ganz links verwendet, um festzustellen, ob die Zahl positiv oder negativ ist.
  3. Ganzzahlen mit Vorzeichen können sowohl positive als auch negative Zahlen enthalten.

Irgendwelche anderen Unterschiede?

Shimmy Weitzhandler
quelle
6
Da 0 weder positiv noch negativ ist , ist es besser, für vorzeichenlose Ganzzahlen den Begriff nicht negativer Wert anstelle des positiven Werts zu verwenden.
Daniel

Antworten:

344

Unsigned kann einen größeren positiven Wert und keinen negativen Wert enthalten.

Ja.

Unsigned verwendet das führende Bit als Teil des Werts, während die signierte Version das Bit ganz links verwendet, um festzustellen, ob die Zahl positiv oder negativ ist.

Es gibt verschiedene Möglichkeiten, vorzeichenbehaftete Ganzzahlen darzustellen. Am einfachsten zu visualisieren ist es, das Bit ganz links als Flag ( Vorzeichen und Größe ) zu verwenden. Häufiger ist jedoch das Zweierkomplement . Beide werden in den meisten modernen Mikroprozessoren verwendet - Gleitkomma verwendet Vorzeichen und Größe, während Ganzzahlarithmetik das Zweierkomplement verwendet.

Ganzzahlen mit Vorzeichen können sowohl positive als auch negative Zahlen enthalten.

Ja

Greg
quelle
Ich bin mir nicht sicher, ob dies genau dieser Text ist, aber ich habe einen anderen Link gefunden. Gehen Sie zur 9. Seite des PDF (es ist eigentlich die 38. Seite des Buches) und Sie können den Abschnitt mit dem Namen Datendarstellung (Abschnitt 1.3) sehen. Es enthält die Erklärung aller oben genannten Dinge. lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…
WeirdElfB0y
92

Ich werde auf Hardwareebene auf x86 auf Unterschiede eingehen. Dies ist meistens irrelevant, es sei denn, Sie schreiben einen Compiler oder verwenden Assemblersprache. Aber es ist schön zu wissen.

Erstens unterstützt x86 native die komplementäre Darstellung signierter Zahlen durch die beiden . Sie können andere Darstellungen verwenden, dies würde jedoch mehr Anweisungen erfordern und im Allgemeinen eine Verschwendung von Prozessorzeit bedeuten.

Was meine ich mit "nativer Unterstützung"? Grundsätzlich meine ich, dass es eine Reihe von Anweisungen gibt, die Sie für vorzeichenlose Nummern verwenden, und eine andere Reihe, die Sie für vorzeichenbehaftete Nummern verwenden. Vorzeichenlose Nummern können in denselben Registern wie vorzeichenbehaftete Nummern gespeichert werden, und Sie können vorzeichenbehaftete und vorzeichenlose Anweisungen mischen, ohne den Prozessor zu beunruhigen. Es ist Sache des Compilers (oder Assembler-Programmierers), zu verfolgen, ob eine Nummer signiert ist oder nicht, und die entsprechenden Anweisungen zu verwenden.

Erstens haben Zweierkomplementzahlen die Eigenschaft, dass Addition und Subtraktion genauso sind wie bei vorzeichenlosen Zahlen. Es macht keinen Unterschied, ob die Zahlen positiv oder negativ sind. (Also mach einfach weiter und ADDund SUBdeine Zahlen ohne Sorge.)

Die Unterschiede zeigen sich bei Vergleichen. x86 hat eine einfache Möglichkeit, sie zu unterscheiden: oben / unten zeigt einen vorzeichenlosen Vergleich an und größer / kleiner als ein vorzeichenbehafteter Vergleich. (ZB JAEbedeutet "Springen, wenn über oder gleich" und ist ohne Vorzeichen.)

Es gibt auch zwei Sätze von Multiplikations- und Divisionsanweisungen, um mit vorzeichenbehafteten und vorzeichenlosen Ganzzahlen umzugehen.

Zuletzt: Wenn Sie beispielsweise nach einem Überlauf suchen möchten, würden Sie dies für signierte und nicht signierte Nummern unterschiedlich tun.

Artelius
quelle
Was meinst du mit vorzeichenlosen und vorzeichenlosen Zahlen? Ich möchte fragen, ob ich vorzeichenlose int a = 2 und vorzeichenlose int b = 2 schreibe, damit beide vorzeichenlos oder vorzeichenlos sind. Hängt eine signierte oder vorzeichenlose Nummer vom Typ ab? wir weisen es zu oder hängt davon ab, ob es ein negatives Vorzeichen hat oder nicht? Das nervt mich schon eine Weile.
Suraj Jain
@SurajJain signiert und nicht signiert beziehen sich auf Typen. Sie zeigen an, ob es möglich für eine Variable oder einen Ausdruck einen negativen Wert zu haben.
Artelius
Ich habe den folgenden Zweifel, ich habe die Frage gestellt, noch keine zufriedenstellende Antwort, werfen Sie einen Blick hier, stackoverflow.com/questions/41399092/…
Suraj Jain
62

Er fragte nur nach unterschrieben und nicht unterschrieben. Ich weiß nicht, warum die Leute hier zusätzliche Dinge hinzufügen. Lass mich dir die Antwort sagen.

  1. Ohne Vorzeichen: Es besteht nur aus nicht negativen Werten, dh 0 bis 255.

  2. Signiert: Es besteht sowohl aus negativen als auch aus positiven Werten, jedoch in unterschiedlichen Formaten wie

    • 0 bis +127
    • -1 bis -128

Und diese Erklärung bezieht sich auf das 8-Bit-Zahlensystem.

Ashish Kumar
quelle
17

Nur ein paar Punkte der Vollständigkeit halber:

  • In dieser Antwort werden nur ganzzahlige Darstellungen behandelt. Es kann andere Antworten für Gleitkomma geben;

  • Die Darstellung einer negativen Zahl kann variieren. Das heute am häufigsten verwendete (bei weitem fast universelle) ist das Zweierkomplement . Andere Darstellungen umfassen das eigene Komplement (ziemlich selten) und die vorzeichenbehaftete Größe (verschwindend selten - wahrscheinlich nur für Museumsstücke verwendet), wobei einfach das hohe Bit als Vorzeichenindikator verwendet wird, wobei die verbleibenden Bits den absoluten Wert der Zahl darstellen.

  • Bei Verwendung des Zweierkomplements kann die Variable einen größeren Bereich (um eins) negativer Zahlen als positive Zahlen darstellen. Dies liegt daran, dass Null in den 'positiven' Zahlen enthalten ist (da das Vorzeichenbit nicht für Null gesetzt ist), aber nicht in den negativen Zahlen. Dies bedeutet, dass der Absolutwert der kleinsten negativen Zahl nicht dargestellt werden kann.

  • Wenn Sie das eigene Komplement oder die vorzeichenbehaftete Größe verwenden, kann Null entweder als positive oder negative Zahl dargestellt werden (was einer der Gründe ist, warum diese Darstellungen normalerweise nicht verwendet werden).

Michael Burr
quelle
Wenn ich vorzeichenloses int a = -2 und vorzeichenloses int b = -2 schreibe, würde die zugrunde liegende Darstellung dieselbe sein. Ich weiß, dass es nicht gut ist, vorzeichenlose Zahlen mit einem negativen Wert zu versehen, aber wenn ich sie gebe, was wird das sein? zugrunde liegende Darstellung?
Suraj Jain
1
Minor niggle: Vorzeichen und Größe werden im IEEE-Gleitkomma verwendet, daher ist dies eigentlich recht häufig. :-)
Alastair
14

Nach dem, was wir in der Klasse gelernt haben, können vorzeichenbehaftete Ganzzahlen sowohl positive als auch negative Zahlen darstellen, während vorzeichenlose Ganzzahlen nur nicht negativ sind.

Betrachten Sie beispielsweise eine 8-Bit- Zahl:

vorzeichenlose Werte 0an255

signierte Werte reichen von -128zu127

Ying Xiong
quelle
11

Alles außer Punkt 2 ist korrekt. Es gibt viele verschiedene Notationen für signierte Ints, einige Implementierungen verwenden die erste, andere die letzte und wieder andere etwas völlig anderes. Das hängt alles von der Plattform ab, mit der Sie arbeiten.

Jasper Bekkers
quelle
Ist das das Little-Endian- und das Big-Endian-Ding?
VIceBerg
Little vs. Big Endian hat mit der Reihenfolge der Bytes auf der Plattform zu tun. Little Endian kann 0xFF 0xFE 0x7F ausführen, während Big Endian 0x7F 0xFE 0xFF ausführt.
Jasper Bekkers
10

Ein weiterer Unterschied besteht darin, dass Sie zwischen Ganzzahlen unterschiedlicher Größe konvertieren.

Wenn Sie beispielsweise eine Ganzzahl aus einem Bytestream (der Einfachheit halber 16 Bit) mit vorzeichenlosen Werten extrahieren, können Sie Folgendes tun:

i = ((int) b[j]) << 8 | b[j+1]

(sollte wahrscheinlich das 2. Byte umwandeln , aber ich vermute, der Compiler wird das Richtige tun)

Bei signierten Werten müssten Sie sich um die Zeichenerweiterung kümmern und Folgendes tun:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
Mike Gleen
quelle
5

Im Allgemeinen ist das richtig. Ohne mehr darüber zu wissen, warum Sie nach den Unterschieden suchen, kann ich mir keine anderen Unterscheidungsmerkmale zwischen signiert und nicht signiert vorstellen.

toddk
quelle
4

Über das hinaus, was andere gesagt haben, können Sie in C eine vorzeichenlose Ganzzahl nicht überlaufen lassen. Das Verhalten wird als Modularithmetik definiert. Sie können eine vorzeichenbehaftete Ganzzahl überlaufen lassen, und theoretisch (wenn auch nicht in der Praxis bei aktuellen Mainstream-Systemen) kann der Überlauf einen Fehler auslösen (möglicherweise ähnlich einem Fehler durch Teilen durch Null).

Jonathan Leffler
quelle
1
Beachten Sie, dass ein vorzeichenbehafteter Ganzzahlüberlauf undefiniertes Verhalten auslöst und moderne Compiler äußerst aggressiv sind, wenn es darum geht, dies zu erkennen und auszunutzen, um Ihr Programm auf unerwartete, aber technisch legitime Weise zu ändern, da sie davon ausgehen dürfen, dass undefiniertes Verhalten nicht auftritt - grob gesagt. Dies ist heute ein viel größeres Problem als vor 7 Jahren.
Jonathan Leffler
4
  1. Ja, eine Ganzzahl ohne Vorzeichen kann einen großen Wert speichern.
  2. Nein, es gibt verschiedene Möglichkeiten, positive und negative Werte anzuzeigen.
  3. Ja, eine vorzeichenbehaftete Ganzzahl kann sowohl positive als auch negative Werte enthalten.
Bhavesh
quelle
4

(als Antwort auf die zweite Frage) Wenn Sie nur ein Vorzeichenbit (und nicht das Zweierkomplement) verwenden, können Sie am Ende -0 erhalten. Nicht sehr hübsch.

Ryan Rodemoyer
quelle
Nur um diese Antwort zu ergänzen, bedeutet es im Grunde, dass 10 == 00, wobei beide Zahlen Basis 2 sind.
4

Vorzeichenbehaftete Ganzzahlen in C stehen für Zahlen. Wenn aund bVariablen von vorzeichenbehafteten Ganzzahltypen sind, verlangt der Standard niemals, dass ein Compiler den Ausdrucksspeicher a+=bin aetwas anderes als die arithmetische Summe ihrer jeweiligen Werte umwandelt. Wenn die arithmetische Summe nicht passen würde a, könnte der Prozessor sie möglicherweise nicht dort ablegen, aber der Standard würde nicht erfordern, dass der Compiler den Wert abschneidet oder umschließt oder irgendetwas anderes tut, wenn die Werte überschritten werden die Grenzen für ihre Typen. Beachten Sie, dass C-Implementierungen arithmetische Überläufe mit vorzeichenbehafteten Werten abfangen dürfen, obwohl der Standard dies nicht erfordert.

Ganzzahlen ohne Vorzeichen in C verhalten sich wie abstrakte algebraische Ringe von Ganzzahlen, die kongruent modulo mit einer Zweierpotenz sind, außer in Szenarien, die Konvertierungen in oder Operationen mit größeren Typen beinhalten. Das Konvertieren einer Ganzzahl beliebiger Größe in einen 32-Bit-Typ ohne Vorzeichen ergibt das Element, das den Dingen entspricht, die mit dieser Ganzzahl mod 4,294,967,296 kongruent sind. Der Grund für das Subtrahieren von 3 von 2 ergibt 4.294.967.295, dass das Hinzufügen von etwas Kongruentem zu 3 zu etwas Kongruentem zu 4.294.967.295 etwas Kongruentes zu 2 ergibt.

Abstrakte algebraische Ringtypen sind oft praktisch; Leider verwendet C die Vorzeichen als entscheidenden Faktor dafür, ob sich ein Typ als Ring verhalten soll. Schlimmer noch, vorzeichenlose Werte werden bei der Konvertierung in größere Typen eher als Zahlen als als Ringelemente behandelt, und vorzeichenlose Werte, die kleiner sind als intdie Umwandlung in Zahlen, wenn eine Arithmetik für sie ausgeführt wird. Wenn va uint32_tgleich ist 4,294,967,294, dann v*=v;sollte machen v=4. Wenn intes sich um 64 Bit handelt, ist leider nicht abzusehen, was v*=v;dies tun könnte.

In Anbetracht des Standards würde ich vorschlagen, vorzeichenlose Typen in Situationen zu verwenden, in denen das mit algebraischen Ringen verbundene Verhalten gewünscht wird, und vorzeichenbehaftete Typen, wenn Zahlen dargestellt werden sollen. Es ist bedauerlich, dass C die Unterscheidungen so getroffen hat, aber sie sind das, was sie sind.

Superkatze
quelle
3

Ganzzahlen ohne Vorzeichen fangen Sie mit größerer Wahrscheinlichkeit in einer bestimmten Falle als Ganzzahlen mit Vorzeichen. Die Falle kommt von der Tatsache, dass, obwohl 1 & 3 oben korrekt sind, beiden Arten von Ganzzahlen ein Wert zugewiesen werden kann, der außerhalb der Grenzen dessen liegt, was er "halten" kann, und dass er stillschweigend konvertiert wird.

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

Wenn Sie dies ausführen, erhalten Sie die folgende Ausgabe, obwohl beide Werte -1 zugewiesen und unterschiedlich deklariert wurden.

signed < 0
-1 == -1
4294967295d == 4294967295d
Matthew
quelle
0

Der einzige garantierte Unterschied zwischen einem vorzeichenbehafteten und einem vorzeichenlosen Wert in C besteht darin, dass der vorzeichenbehaftete Wert negativ, 0 oder positiv sein kann, während ein vorzeichenloser Wert nur 0 oder positiv sein kann. Das Problem ist, dass C das Format der Typen nicht definiert (Sie wissen also nicht , dass Ihre Ganzzahlen in Zweierkomplementen vorliegen ). Genau genommen sind die ersten beiden Punkte, die Sie erwähnt haben, falsch.

Klarer
quelle
0

Sie müssen vorzeichenlose Ganzzahlen verwenden, wenn Sie auf eingebetteten Systemen programmieren. Wenn in Schleifen keine vorzeichenbehafteten Ganzzahlen erforderlich sind, spart die Verwendung vorzeichenloser Ganzzahlen die Sicherheit, die für den Entwurf solcher Systeme erforderlich ist.

Fahad Naeem
quelle