negative ganze Zahl 31 = -1 nicht 1? [Duplikat]

7

also, sagen wir, ich habe eine vorzeichenbehaftete ganze Zahl (einige Beispiele):

%Vor%

jetzt: -1101363339 >> 31 zum Beispiel sollte gleich 1 richtig sein? aber auf meinem Computer bekomme ich -1. Unabhängig davon, welche negative ganze Zahl ich wähle, wenn x = negative Zahl, x >> 31 = -1 . Warum? klar in binär sollte es 1 sein.

    
dgamma3 21.06.2013, 00:13
quelle

4 Antworten

19

Per C99 6.5.7 Bitweise Verschiebung Operatoren:

  

Wenn E1 einen Typ mit Vorzeichen und einen negativen Wert hat, ist der resultierende Wert implementierungsdefiniert.

wobei E1 die linke Seite des Shift-Ausdrucks ist. Es hängt also von deinem Compiler ab, was du bekommst.

    
Jeff Walden 21.06.2013, 00:17
quelle
10

In den meisten Sprachen wird bei einer Verschiebung nach rechts eine arithmetische Verschiebung vorgenommen, dh das höchstwertige Bit wird beibehalten. Daher haben Sie in Ihrem Fall alle 1 in binär, was -1 in Dezimal ist. Wenn Sie unsigned int verwenden, erhalten Sie das Ergebnis, das Sie suchen.

Per C 2011 6.5.7 Bitweise Verschiebung Operatoren :

  

Das Ergebnis von E1 >> E2 ist E1 rechtsverschobene E2 Bitpositionen. Wenn E1 einen vorzeichenlosen Typ hat   oder wenn E1 einen signierten Typ und einen nichtnegativen Wert hat, ist der Wert des Ergebnisses das Integral   Teil des Quotienten von E1 / 2 E2 . Wenn E1 einen signierten Typ und einen negativen Wert hat, wird der   Der resultierende Wert ist implementierungsdefiniert.

Grundsätzlich ist die Rechtsverschiebung einer Ganzzahl mit Vorzeichen mit Vorzeichen eine Implementierung, aber die meisten Implementierungen entscheiden sich für eine arithmetische Verschiebung.

    
aaronman 21.06.2013 00:15
quelle
5

Das Verhalten, das Sie sehen, wird als arithmetische Verschiebung bezeichnet, bei der die Verschiebung nach rechts das Zeichenbit erweitert. Dies bedeutet, dass die MSBs den gleichen Wert wie das ursprüngliche Vorzeichenbit tragen. Mit anderen Worten, eine negative Zahl ist nach einer Linksverschiebung immer negativ.

Beachten Sie, dass dieses Verhalten in der Implementierung definiert ist und nicht mit einem anderen Compiler garantiert werden kann.

    
Code-Apprentice 21.06.2013 00:15
quelle
2

Was Sie sehen, ist eine arithmetische Verschiebung, im Gegensatz zu der bitweisen Verschiebung, die Sie erwartet haben; h., der Compiler propagiert das "Vorzeichen" -Bit, anstatt die Bits "brutal" zu verschieben, und dividiert dadurch durch 2 N

Wenn Sie von unsigned int s und positiv int s sprechen, ist eine Rechtsverschiebung eine sehr einfache Operation - die Bits werden um eine Stelle nach rechts verschoben (0 auf der linken Seite einfügen), unabhängig von ihrer Bedeutung. In solchen Fällen ist die Operation gleichbedeutend mit dividieren durch 2 N <(und tatsächlich definiert der C-Standard dies so).

Die Unterscheidung kommt auf, wenn über negative Zahlen gesprochen wird. Es gibt mehrere Negativzahlen, obwohl derzeit für Ganzzahlen die Zweierkomplementdarstellung verwendet wird.

Das Problem einer "brutalen" bitweisen Verschiebung ist hier zunächst, dass eines der Bits in irgendeiner Weise verwendet wird, um das Zeichen auszudrücken; Daher kann das Verschieben der Binärzahlen unabhängig von der Darstellung negativer Ganzzahlen zu unerwarteten Ergebnissen führen.

Zum Beispiel ist das höchstwertige Bit üblicherweise in der 2er-Darstellung 1 für negative Zahlen, 0 für positive Zahlen; eine bitweise Verschiebung (mit Nullen, die auf der linken Seite eingefügt sind) zu einer negativen Zahl würde dies (unter anderen Dingen) positiv machen, was nicht zu der (normalerweise erwarteten) Division durch 2

führt

Also wird arithmetische Verschiebung eingeführt; Negative Zahlen, die im Zweierkomplement dargestellt sind, haben eine interessante Eigenschaft: Die Division durch 2 N / N-Verhalten der Verschiebung bleibt erhalten, wenn Sie anstelle von Nullen von links Bits einfügen, die den gleichen Wert des Originals haben Zeichenbit.

Auf diese Weise können vorzeichenbehaftete Divisionen durch 2 N mit nur ein wenig extra Logik in der Verschiebung ausgeführt werden, ohne auf eine vollwertige Divisionsroutine zurückgreifen zu müssen.

Ist die arithmetische Verschiebung für Ganzzahlen mit Vorzeichen garantiert? In einigen Sprachen ja 1 , aber in C ist es nicht so - das Verhalten der Verschiebungsoperatoren beim Umgang mit negativen ganzen Zahlen bleibt als implementationsdefiniertes Detail übrig.

Wie so oft, liegt das an der unterschiedlichen Hardware-Unterstützung für den Vorgang; C wird auf sehr unterschiedlichen Plattformen verwendet, und insbesondere in der Vergangenheit gab es je nach Plattform einen großen Unterschied bei den "Kosten" der Operationen.

Wenn der Prozessor beispielsweise keinen arithmetischen Rechtsverschiebungsbefehl bereitstellt, würde der Compiler angewiesen werden, einen viel langsameren DIV -Befehl irgendeiner Art auszugeben, was ein Problem in einer inneren Schleife bei langsameren Prozessoren sein könnte. Aus diesen Gründen überlässt es der C-Standard dem Implementierer, das für die aktuelle Plattform am besten geeignete zu tun.

In Ihrem Fall hat Ihre Implementierung wahrscheinlich die arithmetische Verschiebung gewählt, weil Sie auf einem x86-Prozessor laufen, der 2-Komplement-Arithmetik und verwendet bietet bitweise und arithmetische Verschiebung als Einzel-CPU-Befehle .

  1. Tatsächlich haben Sprachen wie Java sogar arithmetische und bitweise Shift-Operatoren getrennt - dies liegt hauptsächlich an der Tatsache, dass sie keine unsigned -Typen z. speicher Bitfelder.
Matteo Italia 21.06.2013 01:48
quelle

Tags und Links