C # / XNA - Multiplikation schneller als Division?

8

Ich habe kürzlich einen Tweet gesehen, der mich verwirrt hat (dieser wurde von einem XNA-Programmierer geschrieben, im Zusammenhang mit dem Schreiben eines XNA-Spiels):

Microoptimization Tipp des Tages: Wenn möglich, verwenden Sie Multiplikation statt Division in Hochfrequenzbereichen. Es ist ein paar Zyklen schneller.

Ich war ziemlich überrascht, weil ich immer dachte, Compiler seien ziemlich schlau (zum Beispiel mit Bit-Shifting), und habe kürzlich ein Post von Shawn Hargreaves sagt viel dasselbe . Ich habe mich gefragt, wie viel Wahrheit darin steckt, denn in meinem Spiel gibt es viele Berechnungen.

Ich erkundigte mich, hoffte auf eine Probe, aber das Original-Poster konnte es nicht geben. Er hat dies jedoch gesagt:

Nicht unbedingt wenn es etwas wie "center = width / 2" ist. Und ich habe schon entschieden "Ja, es ist es wert". :)

Also, ich bin neugierig ...

Kann jemand ein Beispiel für einen Code geben, bei dem Sie eine Division in eine Multiplikation ändern und einen Leistungszuwachs erzielen können, wobei der C # -Compiler nicht in der Lage war, das Gleiche selbst zu tun.

    
Danny Tuppeny 19.02.2011, 22:01
quelle

4 Antworten

7

Die meisten Compiler können eine vernünftige Arbeit zur Optimierung leisten, wenn Sie ihnen eine Chance geben. Zum Beispiel, wenn Sie durch eine Konstante teilen, sind die Chancen ziemlich gut, dass der Compiler das optimieren kann / wird, so dass es ungefähr so ​​schnell geht wie alles, was Sie vernünftigerweise dafür ersetzen können.

Wenn Sie jedoch zwei Werte haben, die nicht vorher bekannt waren, und Sie müssen eine durch die andere teilen, um die Antwort zu erhalten. Wenn es viel Weg für den Compiler gäbe, viel damit zu tun, würde es - und wenn es viel Platz für den Compiler gab, um es viel zu optimieren, würde die CPU es tun, so dass der Compiler das nicht tun musste.

Bearbeiten: Ihre beste Wette für so etwas (das ist einigermaßen realistisch) wäre wahrscheinlich etwas wie:

%Vor%

Dies ist relativ einfach zu etwas wie:

zu konvertieren %Vor%

Ich kann nicht wirklich garantieren, dass der eine oder andere Compiler das tut. Es ist im Grunde eine Kombination aus Stärkereduzierung und Schleifenhub - es gibt sicherlich Optimierer, die wissen, wie man beides macht, aber was ich vom C # -Compiler gesehen habe, deutet darauf hin, dass es vielleicht nicht funktioniert (aber ich habe nie genau so etwas getestet und das Tests, die ich gemacht habe, waren ein paar Versionen zurück ...)

    
Jerry Coffin 19.02.2011, 22:30
quelle
4

Obwohl der Compiler Divisionen und Multiplikationen mit Potenzen von 2 optimieren kann, können andere Zahlen schwierig oder unmöglich zu optimieren sein. Versuchen Sie, eine Division um 17 zu optimieren, und Sie werden sehen, warum. Das geht natürlich davon aus, dass der Compiler nicht weiß, dass Sie vorher durch 17 dividieren (es ist eine Laufzeitvariable, keine Konstante).

    
Darkhydro 19.02.2011 22:34
quelle
3

Etwas spät, aber macht nichts.

Die Antwort auf Ihre Frage ist ja.

Sehen Sie sich meinen Artikel hier an, Ссылка , der Informationen verwendet, die auf dem in Artikel erwähnten Artikel basieren der erste Kommentar zu Ihrer Frage.

Ich habe eine QuickDivideInfo-Struktur, die die magische Zahl und die Verschiebung für einen gegebenen Divisor speichert, wodurch Division und Modulo mit schneller Multiplikation berechnet werden können. Ich habe QuickDivideInfos für eine Liste von Golden Prime Numbers vorberechnet (und getestet!). Für mindestens x64 ist die .Divide-Methode auf QuickDivideInfo inline und ist 3x schneller als der Divide-Operator (auf einem i5); Es funktioniert für alle Zähler außer int.MinValue und kann nicht überlaufen, da die Multiplikation vor dem Verschieben in 64 Bits gespeichert wird. (Ich habe x86 nicht ausprobiert, aber wenn es aus irgendwelchen Gründen nicht inline ist, dann wäre die Ordentlichkeit der Divide-Methode verloren und Sie müssten sie manuell inline einfügen).

Also funktioniert das obige in allen Szenarien (außer int.MinValue), wenn Sie vorberechnen können. Wenn Sie dem Code vertrauen, der die magische Zahl / Verschiebung erzeugt, können Sie zur Laufzeit mit jedem Teiler arbeiten.

Andere bekannte kleine Teiler mit einer sehr begrenzten Anzahl von Zählern können inline geschrieben werden und sind möglicherweise schneller, wenn sie keine Zwischenlänge benötigen.

Division durch ein Vielfaches von zwei: Ich würde erwarten, dass der Compiler sich mit diesem (wie in Ihrer Breite / 2) Beispiel beschäftigt, da es konstant ist. Wenn dies nicht der Fall ist, ändern Sie es in Breite & gt; & gt; 1 sollte in Ordnung sein

    
Simon Hewitt 25.05.2011 18:31
quelle
0

Um einige Zahlen zu geben, auf dieser pdf

Ссылка

vom Pentium bekommen wir einige Zahlen, und sie sind nicht gut:

  • IMUL 10 oder 11
  • FMUL 3 + 1
  • IDIV 46 (32-Bit-Operand)
  • FDIV 39

Wir sprechen von großen Unterschieden

    
xanatos 19.02.2011 22:09
quelle