2017-04-10 3 views
0

Ich verwende SHL/SHR, um eine Zahl in einem Register zu halbieren. Es funktioniert tatsächlich gut mit positiven und negativen Zahlen; aber es gibt etwas, das mich über negative Zahlen nervt.x86 assembly - Wie benutzt man SHR, um eine negative Zahl effektiv zu halbieren?

Bevor ich weitergehen soll ich sagen, ich bin mir dessen bewusst SAR und SAL zu signierte binäre zu verschieben, aber ich brauche SHL/SHR speziell zu verwenden. (Ich habe versucht, SAR und SAL und diese funktionierten schön - aber ich kann diese nicht verwenden)

Also auf das Problem.

Wenn ich eine Nummer habe, sagen wir -5, die im Register als "FFFFFFFB" gespeichert ist.

Aber wenn ich SHR es (um es zu halbieren) wird es behandelt, als wäre es 4.294.967.291. Es funktioniert immer noch für meine Zwecke, aber anstatt halbiert -5 (das würde 3 Schleifen, um 0 zu erreichen) es halbiert diese riesige Zahl und nimmt mehr Schleifen (32 Schleifen). Das nervt mich als sehr ineffizient. Gibt es einen Trick, um es als ein -5 statt 4.294.967.291 zu sehen?

Ich dachte, um zu überprüfen, ob die Nummer negativ ist, speichern Sie das in einem Register. Arbeite daran, als ob es positiv wäre, dann überprüfe mein neg/pos-Register und ordne das Zeichen entsprechend zu?

Aber dieser Ansatz klingt nicht richtig für mich?
Aber andererseits bin ich neu in Assembly und weiß nicht wirklich, ob das ist die Art von was ich für diese Art von Problem tun soll?

+5

Wenn Sie wissen, 'sar' dann wissen Sie, was es tut. Also emulieren Sie es mit 'shr' und etwas anderem. PS: Ihr Ansatz würde auch funktionieren. Erwarten Sie nichts "effektives", da der effektive (effiziente?) Weg "sar" ist. – Jester

+0

Wohlgemerkt, diese Verschiebungsteilung ist nicht korrekt für den Wert -1 (sar -1 == -1, nicht Null). Ansonsten ist der 'sar' die beste Lösung dafür. Wenn Sie 'sar' nicht verwenden können, nur andere Anweisungen, dann sollten Sie studieren, was' sar' tut, und es mit anderen Anweisungen emulieren. – Ped7g

Antwort

1

Wie Sie vermutet, werden Sie das Vorzeichenbit merken müssen:

MOV EAX,[TheValue] 
MOV EDX,EAX 
AND EDX,0x80000000 ; remember sign bit from EAX 
SHR EAX,1 
OR EAX,EDX   ; and put it back 

Das wird richtig sowohl positive als auch negative Werte halbieren. Ergebnis ist in EAX.

+0

Neugierig, warum das Problem an erster Stelle steht. Warum verschiebt die Verschiebung nach rechts auch das Vorzeichenbit und als Nebeneffekt macht es eine große positive Zahl? Ist es nicht nur der Zweck (Zeichen zu speichern), in welchem ​​Fall wäre es nützlich, es aus der Position zu verschieben? – Duxa

+0

Das Vorzeichenbit ist das oberste Bit in diesem Fall der 32-Bit-Wert. Wenn Sie den Wert als unsigned behandeln möchten, ist das oberste Bit genau das, das höchste Bit, nicht das Vorzeichenbit. Das ist das Schöne am Zweierkomplement. Und der vorzeichenlose Wert '0x80000000' kann halbiert werden, indem man ihn einmal nach rechts verschiebt:' 0x40000000'. In Assembler sind 32 Bits 32 Bits und es hängt von Ihnen ab, ob Sie sie als signiert oder als nicht signiert behandeln wollen. –