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) 

Antworten auf die Frage(2)

Ihre Antwort auf die Frage