Multiplizieren Sie mit 0,5, anstatt durch 2 zu dividieren
Lesezeit: 3 Minuten
Niko
Während ich Tipps in C gelesen habe, habe ich diesen Tipp hier gesehen http://www.cprogramming.com/tips/tip/multiply-rather-than-divide
aber ich bin mir nicht sicher. Mir wurde gesagt, dass sowohl Multiplizieren als auch Dividieren langsamer und zeitaufwändiger sind und viele Zyklen erfordern.
und ich habe Leute oft gesehen i << 2 Anstatt von i x 4 weil das Schalten schneller ist.
Ist es ein guter Tipp mit x0.5 or /2 ? oder aber moderne Compiler optimieren es besser?
i * 0.5 ist nicht immer gleich i / 2 (wenn i ist ein intdie Division ist ganzzahlig und nicht Gleitkomma)
– SheetJS
10. August 2013 um 18:28 Uhr
Sie sollten Ihren Code klar schreiben (i * 4 und i / 2) und aktivieren Sie Compiler-Optimierungen. Compiler sind sehr gut in diesen Optimierungen.
– Hochofen
10. August 2013 um 18:34 Uhr
Wenn die Profilerstellung einen Leistungsengpass zeigt und Sie bessere Algorithmen und Datenstrukturen ausgewählt haben, beginnen Sie erst dann mit dem Ausprobieren und Testen dieser Mikrooptimierungen. Es ist eine effektivere Nutzung Ihrer Zeit.
– Hochofen
10. August 2013 um 18:39 Uhr
Ein Ort, an dem solche Optimierungen nicht angewendet werden, ist, wenn Integer div/mod/mul durch eine Nichtkonstante ausgeführt wird. Es hat immer noch einen gewissen Wert, diese Handoptimierungen zu lehren. Bei FP-Mathematik werden diese Optimierungen häufig auch nicht durchgeführt, es sei denn, unsichere Optimierungen werden mit dem Compiler aktiviert.
– Cory Nelson
10. August 2013 um 18:39 Uhr
huysentruitw
Es ist wahr, dass einige (wenn nicht die meisten) Prozessoren schneller multiplizieren können als eine Divisionsoperation, aber es ist wie der Mythos von ++i schneller sein als i++ in einer for-Schleife. Ja, das war es einmal, aber heutzutage sind Compiler schlau genug, all diese Dinge für Sie zu optimieren, also sollten Sie sich nicht mehr darum kümmern.
Und was das Bit-Shiften betrifft, es war früher schneller zu verschieben << 2 als mit 4 zu multiplizieren, aber diese Zeiten sind vorbei, da die meisten Prozessoren in einem Taktzyklus multiplizieren können, genau wie ein Schichtbetrieb.
Ein gutes Beispiel dafür war die Berechnung der Pixeladresse in VGA 320x240 Modus. Das haben sie alle gemacht:
address = x + (y << 8) + (y << 6)
um y mit 320 zu multiplizieren. Auf modernen Prozessoren kann dies langsamer sein als nur:
address = x + y * 320;
Also, schreiben Sie einfach, was Sie denken, und der Compiler erledigt den Rest 🙂
Kein mir bekannter Prozessor multipliziert sich in einem Zyklus (Quelle: instlatx64.atw.hu ). (allerdings wird die Multiplikation mit 4 wohl ohnehin vom Compiler auf eine Verschiebung optimiert)
– Harald
10. August 2013 um 18:36 Uhr
@harold: Die Latenz kann> 1 Zyklus betragen, aber der Durchsatz sollte auf den meisten modernen CPUs 1 Zyklus/Mult betragen …
– Oliver Charlesworth
10. August 2013 um 18:39 Uhr
Der Mythos ist wahr: ++i ist schneller als i++, zumindest wenn i ein komplexes Objekt ist. cppreference,.com zitieren: “Da eine temporäre Kopie des Objekts während des Post-Increments und Post-Decrements erstellt wird, sind Pre-Increment- oder Pre-Decrement-Operatoren normalerweise effizienter in Kontexten, in denen der zurückgegebene Wert nicht verwendet wird.”
– Pixelfett
16. August 2017 um 22:12 Uhr
Ich möchte einen neueren Compiler sehen, der nicht intelligent genug ist, um dies zu optimieren, nachdem er erkennt, dass der temporäre Wert nie verwendet wird.
– huysentruitw
16. August 2017 um 23:01 Uhr
@pixelgrease Obwohl dies eine C-Frage ist.
– Davislor
4. September 2018 um 7:05 Uhr
Ich finde, dass dieser Dienst von unschätzbarem Wert ist, um diese Art von Dingen zu testen:
Schauen Sie sich nur die Endmontage an. In 99 % der Fälle werden Sie feststellen, dass der Compiler sowieso alles auf denselben Code optimiert. Verschwenden Sie nicht die Gehirnleistung!
In einigen Fällen ist es besser, es explizit zu schreiben. Zum Beispiel, 2^n (wobei n eine positive ganze Zahl ist) könnte geschrieben werden als (int) pow( 2.0, n ) aber es ist offensichtlich besser zu verwenden 1<<n (und der Compiler wird diese Optimierung nicht für Sie vornehmen). Es kann sich also lohnen, diese Dinge im Hinterkopf zu behalten. Wie bei allem sollten Sie jedoch nicht vorzeitig optimieren.
„mit 0,5 multiplizieren statt durch 2 dividieren“ (2,0) geht schneller weniger Umgebungen heute als früher, hauptsächlich aufgrund verbesserter Compiler, die den Code optimieren.
“benutze i << 2 statt ix 4" geht schneller weniger Umgebungen aus ähnlichen Gründen.
Im auswählen In solchen Fällen muss sich der Programmierer immer noch um solche Probleme kümmern, aber es wird immer seltener. Code Wartung wächst weiterhin als dominierendes Thema. Verwenden Sie also das, was für dieses Code-Snippet am sinnvollsten ist: x*0.5, x/2.0, half(x)etc.
Compiler optimieren leicht Code. Empfehlen Sie Code mit High-Level-Problemen im Auge. Z.B. Ist der Algorithmus O(n) oder O(n*n)?
Der wichtige Gedanke, den es weiterzugeben gilt, ist dieser Die besten Code-Design-Praktiken entwickeln sich weiter und Variationen treten unter den Umgebungen auf. Anpassungsfähig sein. Was heute am besten ist, kann sich in Zukunft verschieben (oder vervielfachen).
kotzminion
Viele CPUs können die Multiplikation in 1 oder 2 Taktzyklen durchführen, aber die Division dauert immer länger (obwohl die FP-Division manchmal schneller ist als die Integer-Division).
Wenn Sie sich diese Antwort ansehen Wie kann ich die Leistung von log() und fp division in C++ vergleichen? Sie werden sehen, dass die Teilung 24 Zyklen überschreiten kann.
Warum dauert die Division so viel länger als die Multiplikation? Wenn Sie sich an die Grundschule erinnern, erinnern Sie sich vielleicht, dass Multiplikationen im Wesentlichen mit vielen gleichzeitigen Additionen durchgeführt werden können. Die Division erfordert eine iterative Subtraktion, die nicht gleichzeitig durchgeführt werden kann und daher länger dauert. Tatsächlich beschleunigen einige FP-Einheiten die Division, indem sie eine reziproke Approximation durchführen und damit multiplizieren. Es ist nicht ganz so genau, aber etwas schneller.
Wenn Sie mit Ganzzahlen arbeiten und als Ergebnis eine Ganzzahl erwarten, ist es besser, sie zu verwenden / 2vermeidet auf diese Weise unnötige Konvertierungen nach/von Float
Wenn Sie mit ganzen Zahlen arbeiten und als Ergebnis eine ganze Zahl erwarten, >> 1 überlegen ist / 2. Der Compiler kann letztere nicht durch erstere ersetzen, da sie für negative Zahlen nicht äquivalent sind (außer wenn das Ergebnis eine ganze Zahl ist, Wissen, das der Programmierer hat, aber der Compiler möglicherweise nicht in der Lage ist, daraus abzuleiten).
– Pascal Cuoq
10. August 2013 um 18:38 Uhr
@PascalCuoq das stimmt, aber der Unterschied verschwindet, wenn Sie mit arbeiten unsigned ints, aus offensichtlichen Gründen. Und wenn Sie mit signierten arbeiten ints, Sie möchten wahrscheinlich kein falsches Verhalten für negative Zahlen.
– David
10. August 2013 um 18:41 Uhr
Es ist nicht falsch, wenn Sie „als Ergebnis eine ganze Zahl erwarten“.
– Pascal Cuoq
10. August 2013 um 18:48 Uhr
@PascalCuoq ah ich verstehe, was du meinst (ich bin zuerst nicht gefolgt, weil du natürlich immer eine ganze Zahl als Ergebnis bekommst!)
– David
10. August 2013 um 20:55 Uhr
Wenn Sie mit ganzen Zahlen arbeiten und als Ergebnis eine ganze Zahl erwarten, >> 1 überlegen ist / 2. Der Compiler kann letztere nicht durch erstere ersetzen, da sie für negative Zahlen nicht äquivalent sind (außer wenn das Ergebnis eine ganze Zahl ist, Wissen, das der Programmierer hat, aber der Compiler möglicherweise nicht in der Lage ist, daraus abzuleiten).
– Pascal Cuoq
10. August 2013 um 18:38 Uhr
@PascalCuoq das stimmt, aber der Unterschied verschwindet, wenn Sie mit arbeiten unsigned ints, aus offensichtlichen Gründen. Und wenn Sie mit signierten arbeiten ints, Sie möchten wahrscheinlich kein falsches Verhalten für negative Zahlen.
– David
10. August 2013 um 18:41 Uhr
Es ist nicht falsch, wenn Sie „als Ergebnis eine ganze Zahl erwarten“.
– Pascal Cuoq
10. August 2013 um 18:48 Uhr
@PascalCuoq ah ich verstehe, was du meinst (ich bin zuerst nicht gefolgt, weil du natürlich immer eine ganze Zahl als Ergebnis bekommst!)
– David
10. August 2013 um 20:55 Uhr
14334100cookie-checkMultiplizieren Sie mit 0,5, anstatt durch 2 zu dividierenyes
i * 0.5
ist nicht immer gleichi / 2
(wenni
ist einint
die Division ist ganzzahlig und nicht Gleitkomma)– SheetJS
10. August 2013 um 18:28 Uhr
Sie sollten Ihren Code klar schreiben (
i * 4
undi / 2
) und aktivieren Sie Compiler-Optimierungen. Compiler sind sehr gut in diesen Optimierungen.– Hochofen
10. August 2013 um 18:34 Uhr
Wenn die Profilerstellung einen Leistungsengpass zeigt und Sie bessere Algorithmen und Datenstrukturen ausgewählt haben, beginnen Sie erst dann mit dem Ausprobieren und Testen dieser Mikrooptimierungen. Es ist eine effektivere Nutzung Ihrer Zeit.
– Hochofen
10. August 2013 um 18:39 Uhr
Ein Ort, an dem solche Optimierungen nicht angewendet werden, ist, wenn Integer div/mod/mul durch eine Nichtkonstante ausgeführt wird. Es hat immer noch einen gewissen Wert, diese Handoptimierungen zu lehren. Bei FP-Mathematik werden diese Optimierungen häufig auch nicht durchgeführt, es sei denn, unsichere Optimierungen werden mit dem Compiler aktiviert.
– Cory Nelson
10. August 2013 um 18:39 Uhr