Optimiert Java die Division durch Zweier-zu-Bit-Verschiebung?

7

Optimiert der Java-Compiler oder den JIT-Compiler Divisionen oder Multiplikationen durch eine konstante Potenz von zwei bis zum Bitshifting?

Sind zum Beispiel die folgenden zwei Aussagen so optimiert, dass sie identisch sind?

%Vor%

(im Grunde diese Frage aber für Java)

    
wchargin 01.09.2013, 17:10
quelle

3 Antworten

8

Nein, der Java-Compiler macht das nicht, weil er nicht sicher sein kann, was das Zeichen von (end - start) sein wird. Warum ist das wichtig? Bitverschiebungen bei negativen Ganzzahlen ergeben ein anderes Ergebnis als eine gewöhnliche Division. Hier können Sie eine Demo sehen: dieser einfache Test :

%Vor%

Beachten Sie auch, dass ich >> anstelle von >>> verwendet habe. A >>> ist ein unsigniertes Bitshift, während >> signiert ist.

%Vor%

@Mystical: Ich habe einen Benchmark geschrieben, der zeigt, dass der Compiler / JVM diese Optimierung nicht durchführt: Ссылка

    
Martijn Courteaux 01.09.2013, 17:17
quelle
11

Während die akzeptierte Antwort in dem Sinne richtig ist, dass die Division nicht einfach durch eine Rechtsverschiebung ersetzt werden kann, ist die Benchmark furchtbar falsch. Jeder Java-Benchmark, der für weniger als eine Sekunde läuft, misst wahrscheinlich die Leistung des Interpreters - nicht etwas, das Ihnen normalerweise wichtig ist.

Ich konnte nicht widerstehen und schrieb einen eigenen Benchmark , der hauptsächlich zeigt dass es alles komplizierter ist. Ich versuche nicht, die Ergebnisse vollständig zu erklären, aber ich kann das sagen

  • eine allgemeine Division ist eine verdammt langsame Operation
  • es wird vermieden, so viel wie möglich
  • Teilung durch eine Konstante bekommt AFAIK immer irgendwie optimiert
  • Division durch eine Zweierpotenz wird durch eine Rechtsverschiebung und eine Anpassung für negative Zahlen ersetzt
  • ein manuell optimierter Ausdruck ist möglicherweise besser
maaartinus 07.02.2014 00:50
quelle
1

Wenn die JVM es nicht tut, können Sie es leicht selbst machen.

Wie bereits erwähnt, verhalten sich Rechtsverschiebungen bei negativen Zahlen nicht gleich wie bei der Division, da das Ergebnis in die falsche Richtung gerundet wird. Wenn Sie wissen, dass die Dividende nicht negativ ist, können Sie die Division sicher durch eine Schicht ersetzen. Wenn es negativ sein könnte, können Sie die folgende Technik verwenden.

Wenn Sie Ihren ursprünglichen Code in diesem Formular ausdrücken können:

%Vor%

Sie können es durch diesen optimierten Code ersetzen:

%Vor%

Oder alternativ:

%Vor%

Diese Formeln kompensieren die falsche Rundung, indem sie eine kleine Zahl addieren, die aus dem Vorzeichenbit des Dividenden berechnet wird. Dies funktioniert für jede x mit allen Shift-Werten von 1 bis 30.

Wenn die Verschiebung 1 ist (d. h., Sie dividieren durch 2), dann kann >> 31 in der ersten Formel entfernt werden, um dieses sehr saubere Snippet zu erhalten:

%Vor%

Ich habe festgestellt, dass diese Techniken schneller sind, selbst wenn die Verschiebung nicht konstant ist, aber offensichtlich profitieren sie am meisten, wenn die Verschiebung konstant ist. Hinweis: Ändern Sie für long x anstelle von int 31 und 32 auf 63 und 64.

Untersuchen des generierten Maschinencodes zeigt, dass die HotSpot Server VM (nicht überraschend) diese Optimierung automatisch durchführen kann, wenn shift ist konstant, aber (auch nicht überraschend) ist die HotSpot Client VM zu dumm um zu funktionieren.

    
Boann 09.02.2014 22:47
quelle