Ich benutze die folgende Funktion, um die Protokollbasis 2 für ganze Zahlen zu berechnen:
public static int log2(int n){
if(n <= 0) throw new IllegalArgumentException();
return 31 - Integer.numberOfLeadingZeros(n);
}
Hat es eine optimale Leistung?
Kennt jemand die J2SE-API-Funktion für diesen Zweck?
UPD1 Überraschenderweise scheint die Gleitkomma- Arithmetik für mich schneller zu sein als die Ganzzahl-Arithmetik.
UPD2 Aufgrund von Kommentaren werde ich detailliertere Untersuchungen durchführen.
UPD3 Meine ganzzahlige arithmetische Funktion ist zehnmal schneller als Math.log (n) /Math.log (2).
java
performance
discrete-mathematics
logarithm
Nullgerät
quelle
quelle
Math.floor(Math.log(n)/Math.log(2))
, so dass es nicht wirklich Log Base 2 berechnet!Antworten:
Wenn Sie darüber nachdenken, Gleitkommawerte für die Ganzzahlarithmetik zu verwenden, müssen Sie vorsichtig sein.
Normalerweise versuche ich, FP-Berechnungen nach Möglichkeit zu vermeiden.
Gleitkommaoperationen sind nicht genau. Sie können nie sicher wissen, was zu
(int)(Math.log(65536)/Math.log(2))
bewerten ist. Zum BeispielMath.ceil(Math.log(1<<29) / Math.log(2))
ist 30 auf meinem PC, wo es mathematisch genau 29 sein sollte. Ich habe keinen Wert für x gefunden, wo(int)(Math.log(x)/Math.log(2))
fehlschlägt (nur weil es nur 32 "gefährliche" Werte gibt), aber das bedeutet nicht, dass es funktioniert auf jedem PC genauso.Der übliche Trick hier ist die Verwendung von "epsilon" beim Runden. Wie
(int)(Math.log(x)/Math.log(2)+1e-10)
sollte niemals scheitern. Die Wahl dieses "Epsilons" ist keine triviale Aufgabe.Mehr Demonstration mit einer allgemeineren Aufgabe - versuchen zu implementieren
int log(int x, int base)
:Der Testcode:
Wenn wir die einfachste Implementierung des Logarithmus verwenden,
dies druckt:
Um Fehler vollständig zu beseitigen, musste ich epsilon hinzufügen, das zwischen 1e-11 und 1e-14 liegt. Könnten Sie dies vor dem Testen gesagt haben? Ich konnte es definitiv nicht.
quelle
strictfp
, nein?strictfp
scheint tatsächlich viel Mist bekommen zu haben, weil er tatsächlich streng ist. :-)return ((long)Math.log(x) / (long)Math.log(base));
es, alle Fehler zu lösen?Dies ist die Funktion, die ich für diese Berechnung verwende:
Es ist etwas schneller als Integer.numberOfLeadingZeros () (20-30%) und fast zehnmal schneller (jdk 1.6 x64) als eine auf Math.log () basierende Implementierung wie diese:
Beide Funktionen geben für alle möglichen Eingabewerte die gleichen Ergebnisse zurück.
Update: Der Java 1.7-Server JIT kann einige statische mathematische Funktionen durch alternative Implementierungen ersetzen, die auf den CPU-Eigenschaften basieren. Eine dieser Funktionen ist Integer.numberOfLeadingZeros (). Bei einer Server-VM ab 1.7 ist eine Implementierung wie die fragliche tatsächlich etwas schneller als die
binlog
oben genannte. Leider scheint die Client-JIT diese Optimierung nicht zu haben.Diese Implementierung liefert auch die gleichen Ergebnisse für alle 2 ^ 32 möglichen Eingabewerte wie die beiden anderen Implementierungen, die ich oben veröffentlicht habe.
Hier sind die tatsächlichen Laufzeiten auf meinem PC (Sandy Bridge i7):
JDK 1.7 32-Bit-Client-VM:
JDK 1.7 x64-Server-VM:
Dies ist der Testcode:
quelle
BSR
Anweisung von x86 funktioniert32 - numberOfLeadingZeros
, ist jedoch für 0 undefiniert. Daher muss ein (JIT) -Compiler auf Nicht-Null prüfen, wenn er nicht beweisen kann, dass dies nicht erforderlich ist. Die BMI-Befehlssatzerweiterungen (Haswell und neuer) wurden eingeführt und in einem einzigen BefehlLZCNT
vollständig implementiertnumberOfLeadingZeros
. Sie sind beide 3-Zyklus-Latenz, 1 pro Zyklus-Durchsatz. Daher würde ich die Verwendung unbedingt empfehlennumberOfLeadingZeros
, da dies eine gute JVM erleichtert. (Das einzig Seltsamelzcnt
ist, dass es eine falsche Abhängigkeit vom alten Wert des Registers hat, das es überschreibt.)Versuchen
Math.log(x) / Math.log(2)
quelle
Sie können die Identität verwenden
Dies würde also für log2 gelten.
Stecken Sie dies einfach in die Java Math Log10-Methode ....
http://mathforum.org/library/drmath/view/55565.html
quelle
Warum nicht:
quelle
Es gibt die Funktion in Guavenbibliotheken:
Also schlage ich vor, es zu benutzen.
quelle
Diese Funktion gibt die Obergrenze des Binärprotokolls einer Zahl zurück, um die x4u-Antwort zu ergänzen, die den Boden des Binärprotokolls einer Zahl angibt:
quelle
Einige Fälle haben gerade funktioniert, als ich Math.log10 verwendet habe:
quelle
Fügen wir hinzu:
Quelle: https://github.com/pochuan/cs166/blob/master/ps1/rmq/SparseTableRMQ.java
quelle
Zur Berechnung der logarithmischen Basis 2 von n kann folgender Ausdruck verwendet werden:
quelle