Zweite Frage zuerst: div
ist eine sehr langsame Anweisung (mehr als 20 Taktzyklen). Die obige Sequenz besteht aus mehr Anweisungen, aber sie sind alle relativ schnell, also ist es ein Nettogewinn in Bezug auf die Geschwindigkeit.
Die ersten fünf Anweisungen (bis einschließlich shrl
) berechnen i/10 (ich werde erklären, wie in einer Minute).
Die nächsten paar Anweisungen multiplizieren das Ergebnis erneut mit 10, aber vermeiden Sie die mul
/imul
Anweisungen (ob dies ein Gewinn ist oder nicht hängt von der genauen Prozessor abzielen - neuere x86s haben sehr schnelle Multiplikatoren, aber ältere nicht).
movl %edx, %eax ; eax=i/10
sall $2, %eax ; eax=(i/10)*4
addl %edx, %eax ; eax=(i/10)*4 + (i/10) = (i/10)*5
addl %eax, %eax ; eax=(i/10)*5*2 = (i/10)*10
Dies wird dann von i
wieder subtrahiert i - (i/10)*10
zu erhalten, welche i % 10
(für Zahlen ohne Vorzeichen).
Schließlich, bei der Berechnung von i/10: Die Grundidee ist, Division durch 10 mit der Multiplikation mit 1/10 zu ersetzen. Der Compiler führt eine Festkomma-Approximation durch Multiplikation mit (2 ** 35/10 + 1) durch - das ist der magische Wert, der in edx
geladen wird, obwohl er als signierter Wert ausgegeben wird, obwohl er wirklich nicht signiert ist Ergebnis um 35. Dies ergibt das richtige Ergebnis für alle 32-Bit-Ganzzahlen.
Es gibt Algorithmen, diese Art von Annäherung zu bestimmen, die garantieren, dass der Fehler kleiner als 1 ist (was für ganze Zahlen bedeutet, es ist der richtige Wert ist) und GCC verwendet offenbar eine :)
Schlussbemerkung: Wenn Sie wirklich wollen siehe GCC compute a modulo, mache die Divisorvariable (zB einen Funktionsparameter), damit diese Art der Optimierung nicht möglich ist. Anyway, auf x86, berechnen Sie modulo mit div
. div
erwartet die 64-Bit-Dividende in edx:eax
(32 Bit hoch in edx, niedrig 32 Bit in eax - clear edx auf Null, wenn Sie mit einer 32-Bit-Zahl arbeiten) und teilt das mit dem von Ihnen angegebenen Operanden (z.div ebx
teilt edx:eax
von). Sie gibt den Quotienten in eax
und den Rest in edx
zurück. idiv
macht das gleiche für vorzeichenbehaftete Werte.
Kennen Sie 32-Bit? –
https://groups.google.com/forum/#!msg/comp.lang.asm.x86/BPkTrwLEgq8/_LbijZ5QD-cJ –
[Ganzzahlige Division durch Konstanten] (http://blogs.msdn.com/b/ devdev/archive/2005/12/12/502980.aspx) –