Schnelle Division auf GCC / ARM
Soweit ich weiß, werden die meisten Compiler eine schnelle Division durchführen, indem sie multiplizieren und dann die Bits nach rechts verschieben. Zum Beispiel, wenn Sie überprüfenDieser SO-Thread Wenn Sie den Microsoft-Compiler auffordern, eine Division durch 10 durchzuführen, wird die Dividende mit 0x1999999A (2 ^ 32/10) multipliziert und das Ergebnis durch 2 ^ 32 dividiert (32 Verschiebungen nach rechts).
So weit, ist es gut.
Als ich dieselbe Division durch 10 in ARM mit GCC getestet habe, hat der Compiler etwas anderes gemacht. Zuerst multiplizierte es die Dividende mit 0x66666667 (2 ^ 34/10), dann dividierte es das Ergebnis durch 2 ^ 34. Bisher ist es dasselbe wie bei Microsoft, außer dass ein höherer Multiplikator verwendet wird. Danach subtrahierte er jedoch (Dividende / 2 ^ 31) vom Ergebnis.
Meine Frage: Warum gibt es in der ARM-Version diese zusätzliche Subtraktion? Können Sie mir ein numerisches Beispiel geben, bei dem das Ergebnis ohne diese Subtraktion falsch ist?
Wenn Sie den generierten Code überprüfen möchten, finden Sie ihn unten (mit meinen Kommentaren):
ldr r2, [r7, #4] @--this loads the dividend from memory into r2
movw r3, #:lower16:1717986919 @--moves the lower 16 bits of the constant
movt r3, #:upper16:1717986919 @--moves the upper 16 bits of the constant
smull r1, r3, r3, r2 @--multiply long, put lower 32 bits in r1, higher 32 in r3
asr r1, r3, #2 @--r3>>2, then store in r1 (effectively >>34, since r3 was higher 32 bits of multiplication)
asr r3, r2, #31 @--dividend>>31, then store in r3
rsb r3, r3, r1 @--r1 - r3, store in r3
str r3, [r7, #0] @--this stores the result in memory (from r3)