Quelle meiner Antwort in:Integer Division durch 7
Is this expression correct in C preprocessor
Ich bin ein wenig aus meinem forten hier, und ich versuche, wie dieses besondere Optimierung Werke zu verstehen.
Wie in der Antwort erwähnt, gcc Integer-Division von 7 optimieren:
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
Welche zurück in C übersetzt:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
Schauen wir uns den ersten Teil einen Blick:
int32_t temp = ((int64_t)num * -015555555555) >> 32;
Warum diese Nummer?
Na, mal 2 nehmen^64 und teilen sie durch 7 und sehen, was herausspringt.
2^64/7 = 2635249153387078802.28571428571428571429
Das sieht wie ein Durcheinander aus, was, wenn wir es in octal umwandeln?
0222222222222222222222.22222222222222222222222
Das ist ein sehr schönes sich wiederholendes Muster, das kann sicherlich kein Zufall sein. Ich meine, wir nicht vergessen, dass 7 0b111
ist und wir wissen, dass, wenn wir durch 99 teilen wir Muster in der Basis zu bekommen neigen zu wiederholen 10. So ist es sinnvoll, dass wir ein sich wiederholendes Muster in der Basis 8 erhalten würde, wenn wir von 7.
Woher kommt unsere Nummer?
(int32_t)-1840700269
ist die gleiche wie (uint_32t)2454267027
* 7 = 17179869189
Und schließlich ist 17179869184 2^34
was bedeutet, dass 17179869189 das nächste Vielfache von 2^7 34 ist. Oder um es anders auszudrücken 2454267027 ist die größte Zahl, die in einem uint32_t
passen, die, wenn multipliziert mit 7 ist sehr nah an eine Potenz von 2
Was in Oktal diese Zahl ist?
0222222222223
Warum ist das wichtig? Nun, wir wollen durch 7 teilen. Diese Zahl ist 2^34/7 ... ungefähr. Wenn wir also 34 mal mit leftshift multiplizieren, sollten wir eine Zahl erhalten, die der genauen Zahl sehr nahe kommt.
die letzten beiden Zeilen schauen, wie sie zu flicken Approximationsfehler entworfen wurden.
Vielleicht hat jemand mit einem wenig mehr Wissen und/oder Know-how in diesem Bereich kann auf diese läutet.
>>> magic = 2454267027
>>> def div7(a):
... if (int(magic * a >> 34) != a // 7):
... return 0
... return 1
...
>>> for a in xrange(2**31, 2**32):
... if (not div7(a)):
... print "%s fails" % a
...
Ausfälle beginnen bei 3435973841 was komischerweise 0b11001100110011001100110011010001
Klassifizieren, warum die Annäherung ein bisschen über mich versagt ist, und warum die Patches es reparieren ist als gut.Weiß jemand, wie die Magie über das hinaus wirkt, was ich hier niedergelegt habe?
http://www.hackersdelight.org/divcMore.pdf –
Dieses PDF war sehr hilfreich bei der Bestimmung der letzten Zeile (sign fix up); Allerdings schien es diesen Algorithmus nicht zu diskutieren, es sei denn, ich habe es verpasst. – OmnipotentEntity
Die definitiven Referenzen sind [hier] (http://gmplib.org/~tege/divcnst-pldi94.pdf) (implementiert im gcc-Compiler) und ein Follow-up [hier] (http://gmplib.org/~tege/division-paper.pdf). Implementierungen finden Sie in der [GMP] (http://gmplib.org/) -Bibliothek. ('udiv_qrnnd_preinv' in' gmp-impl.h') –