Frage

Ich habe C-Code, in dem ich Folgendes mache.

int nPosVal = +0xFFFF;   // + Added for ease of understanding
int nNegVal = -0xFFFF;   // - Added for valid reason

Wenn ich es jetzt versuche

printf ("%d %d", nPosVal >> 1, nNegVal >> 1);

Ich bekomme

32767 -32768

Ist das zu erwarten?

Ich kann so etwas denken

65535 >> 1 = (int) 32767.5 = 32767
-65535 >> 1 = (int) -32767.5 = -32768

Das heißt, -32767,5 wird auf -32768 gerundet.

Ist dieses Verständnis richtig?

War es hilfreich?

Lösung

Es sieht aus wie Ihre Implementierung ist wahrscheinlich eine arithmetische Bit-Verschiebung mit Zweier-Komplement-Zahlen zu tun. In diesem System verschiebt es alle Bits nach rechts und füllt dann in den oberen Bits mit einer Kopie von was auch immer das letzte Bit war. Also für Ihr Beispiel der Behandlung von int als 32-Bit hier:

nPosVal = 00000000000000001111111111111111
nNegVal = 11111111111111110000000000000001

Nach der Verschiebung, haben Sie:

nPosVal = 00000000000000000111111111111111
nNegVal = 11111111111111111000000000000000

Wenn Sie diese zurück in Dezimalzahlen konvertieren, erhalten Sie 32767 und -32768 sind.

Effektiv eine Rechtsverschiebung rundet auf negative Unendlichkeit.

Edit: Nach dem Abschnitt 6.5.7 des neuesten Norm-Entwurf , dieses Verhalten auf negative Zahlen ist die Umsetzung abhängig:

Das Ergebnis der E1 >> E2 E1 rechts verschobenen Positionen E2 Bit. Wenn E1 hat einen unsigned Typen oder wenn E1 ein signiertes Typ und einen nicht-negativen Wert hat, ist der Wert des Ergebnisses der ganzzahlige Teil des Quotienten aus E1 / 2 E2 . Wenn E1 ein signiertes Typ und einen negativen Wert hat, der resultierende Wert ist die Implementierung definiert.

Ihr erklärtes rational für diese:

der C89 Ausschuss die Freiheit bei der Umsetzung von K & R in nicht erforderlich ist die unterzeichnete Rechtsverschiebungsoperation gewährt bestätigt verlängern zu unterzeichnen, da eine solche Anforderung schnellen Code verlangsamen könnte nach unten und da die Nützlichkeit von Zeichen erweitert Verschiebungen ist marginal. (Verschieben eines negativen Zweierkomplement integer arithmetisch richtiger Ort ist nicht die gleichen wie durch zwei dividiert!)

Es ist also abhängig von der Implementierung in der Theorie. In der Praxis habe ich noch nie eine Implementierung nicht Sie eine arithmetische Verschiebung nach rechts, wenn der linken Operanden signiert ist.

gesehen

Andere Tipps

Nein, bekommt man nicht gebrochene Zahlen wie 0,5, wenn sie mit ganzen Zahlen arbeiten. Die Ergebnisse lassen sich leicht erklären, wenn man sich den binären Darstellungen der beiden Zahlen aussehen:

      65535: 00000000000000001111111111111111
     -65535: 11111111111111110000000000000001

Bit Verschiebung nach rechts um ein Bit, und auf der linken Seite erstreckt (beachten Sie, dass dies abhängig von der Implementierung dank Trent):

 65535 >> 1: 00000000000000000111111111111111
-65535 >> 1: 11111111111111111000000000000000

in Dezimalzahlen konvertieren zurück:

 65535 >> 1 = 32767
-65535 >> 1 = -32768

Die C-Spezifikation ist nicht festgelegt, wenn der Vorzeichen-Bit verschoben über oder nicht. Es ist die Umsetzung abhängig.

Wenn Sie mit der rechten Verschiebung, die am wenigsten signifikante Bit verworfen wird.

0xFFFF = 0 1111 1111 1111 1111, die die rechten Verschiebungen geben 0 0111 1111 1111 1111 = 0x7FFF

-0xFFFF = 1 0000 0000 0000 0001 (2s Komplement), die rechten Verschiebungen auf 1 1000 0000 0000 0000 = -0x8000

A-1:Ja.0xffff >> 1 ist 0x7fff oder 32767.Ich bin nicht sicher, was -0xffff tut.Das ist eigenartig.

A-2:Verschieben ist nicht dasselbe wie Teilen.Es handelt sich um eine Bitverschiebung – eine primitive binäre Operation.Dass es manchmal für bestimmte Teilungsarten verwendet werden kann, ist praktisch, aber nicht immer dasselbe.

Unter der C-Ebene haben Maschinen einen CPU-Kern, die vollständig ganze Zahl ist oder skalare . Obwohl in diesen Tagen jeder Desktop-CPU eine FPU hat, war dies nicht immer der Fall und auch heute eingebettete Systeme sind ohne Gleitkommaanweisungen gemacht.

Die heutigen Programmierparadigmen und CPU-Designs und Sprachen aus der Zeit stammen, wo die FPU vielleicht nicht einmal existieren.

So, CPU-Befehle implementieren Festkommaoperationen , in der Regel als rein behandelt integer ops. Nur wenn ein Programm deklariert Elemente von float oder Doppel werden alle Fraktionen bestehen. (Na ja, können Sie die CPU-ops für „festen Punkt“ mit Brüchen verwenden, aber das ist jetzt und war immer recht selten.)

Unabhängig davon, was vorher von einem Sprachstandard Komitee Jahren erforderlich war, alle zumutbaren Maschinen propagieren das Vorzeichenbit auf dem rechten Verschiebungen von Zahlen mit Vorzeichen. Rechtsverschiebungen von unsigned Werten verschieben in Nullen auf der linken Seite. Die Bits herausgeschobenen auf der rechten Seite auf den Boden fallen.

Ihr Verständnis Zur weiteren werden Sie untersuchen müssen "Zweier-Komplement-Arithmetik".

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top