Für Augapfelberechnungen entspricht der Logarithmus zur Basis 2 nahezu dem Logarithmus zur Basis 10 plus dem natürlichen Logarithmus. Offensichtlich ist es besser, eine genauere (und schnellere) Version in ein Programm zu schreiben.
David Thornley
Für ganze Zahlen könnten Sie bei rechter Bitverschiebung eine Schleife ausführen und bei Erreichen von 0 anhalten. Die Anzahl der Schleifen ist eine Annäherung an das Protokoll
Es gibt auch eine nette Bit-Twiddling-Methode dafür (entnommen aus Javas Integer.highestOneBit(int)Methode):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey
37
... oderwhile (i >>= 1) { ++l; }
Lee Daniel Crocker
2
@Joey Das würde funktionieren, wenn die Ganzzahl 32 Bit breit ist, oder? Für 64 Bit hätte es ein Extra i>>32. Da Java jedoch nur 32-Bit-Ints hat, ist dies in Ordnung. Für C / C ++ muss dies berücksichtigt werden.
Ich wollte nur klarstellen - unter Verwendung der Protokollkonvertierungsregeln + der Tatsache, dass log_2 (e) = 1 / log_e (2) -> wir erhalten das Ergebnis
Beachten Sie, dass Sie log10 (2) vorberechnen können, um die Leistung zu steigern.
CorsiKa
@Johannes: Ich bezweifle, dass der Compiler log10 (2) vorberechnet. Der Compiler weiß nicht, dass log10 jedes Mal den gleichen Wert zurückgibt. Nach allem, was der Compiler weiß, kann log10 (2) bei aufeinanderfolgenden Aufrufen unterschiedliche Werte zurückgeben.
Abelenky
@abelenky: Ok, das nehme ich zurück. Da der Compiler die Quelle für die log()Implementierung nie sieht , wird er dies nicht tun. Mein Fehler.
Joey
3
@abelenky: Da log10()eine Funktion im C-Standard definiert ist, kann der Compiler sie "speziell" behandeln, einschließlich der Vorberechnung des Ergebnisses, was meiner Meinung nach @Johannes 'Vorschlag war?
Café
1
@CarlNorum: Ich habe es gerade überprüft und gcc 4.7 wird zumindest log10(2)durch eine Konstante ersetzt.
Café
8
Wenn Sie es schnell machen möchten, können Sie eine Nachschlagetabelle wie in Bit Twiddling Hacks verwenden (nur Ganzzahl log2).
uint32_t v;// find the log base 2 of 32-bit vint r;// result goes herestaticconstintMultiplyDeBruijnBitPosition[32]={0,9,1,10,13,21,2,29,11,14,16,18,22,25,3,30,8,12,20,28,15,17,24,7,19,27,23,6,26,5,4,31};
v |= v >>1;// first round down to one less than a power of 2
v |= v >>2;
v |= v >>4;
v |= v >>8;
v |= v >>16;
r =MultiplyDeBruijnBitPosition[(uint32_t)(v *0x07C4ACDDU)>>27];
Darüber hinaus sollten Sie einen Blick auf Ihren Compiler builtin Methoden nehmen wie _BitScanReversedie könnten schneller sein , weil es vollständig in Hardware berechnet werden.
Warum die Multiplikation und Tabellensuche am Ende? Könnten Sie nicht einfach (v + 1) tun, was auf die nächste Zweierpotenz aufrunden würde? Und dann könnten Sie um eins nach rechts wechseln, um auf die nächste Potenz von 2
abzurunden
@SafayetAhmed Bitte beschreiben Sie, wie Sie mit dieser Methode das log2 einer Nummer finden möchten. Ich kenne keinen einfacheren Weg, um diesen Wert zu erreichen. Neben der Verwendung der obigen Arithmetik mit der Nachschlagetabelle kann ein iterativer / rekursiver Algorithmus oder die Verwendung dedizierter / integrierter Hardware für die Berechnung verwendet werden.
Bkausbk
Angenommen, die Bits einer 32-Bit-Variablen v sind von 0 (LSB) bis N (MSB) nummeriert. Angenommen, das höchstwertige gesetzte Bit von v ist n. Wäre es richtig zu sagen, dass n den Boden darstellt (log2 (v))? Bist du nicht daran interessiert, nur ein gegebenes v zu finden?
Safayet Ahmed
Mir wurde klar, dass das, was ich beschrieben habe, nur die niedrigste Potenz von 2 und nicht den tatsächlichen Logarithmus ergibt. Die Multiplikation und die Tabellensuche dienen dazu, von der Zweierpotenz zum Logarithmus zu gelangen. Sie verschieben die Zahl 0x07C4ACDD um einen gewissen Betrag nach links. Der Betrag, den Sie nach links verschieben, hängt von der Zweierpotenz ab. Die Nummer ist so, dass jede aufeinanderfolgende Folge von 5 Bits eindeutig ist. (0000 0111 1100 0100 0110 1100 1101 1101) gibt Ihnen die Sequenzen (00000) (00001) ... (11101). Je nachdem, wie weit Sie nach links verschieben, erhalten Sie eines dieser 5-Bit-Muster. Dann Tabellensuche. Sehr schön.
Es gibt ein paar Probleme mit dieser Lösung, aber im Allgemeinen ist dies hilfreich, wenn Sie Gleitkommazahlen vermeiden möchten. Sie verlassen sich auf einen Überlauf, damit dies funktioniert, da Sie eine vorzeichenlose Ganzzahl mit -1 initialisieren. Dies kann behoben werden, indem Sie es auf 0 initialisieren und dann den Wert - 1 zurückgeben, vorausgesetzt, Sie prüfen, ob Sie den Fall 0 haben. Das andere Problem ist, dass Sie sich darauf verlassen, dass die Schleife stoppt, wenn n == 0 ist, was Sie explizit angeben sollten. Abgesehen davon ist dies großartig, wenn Sie Gleitkommazahlen vermeiden möchten.
Rian Quinn
2
Sie müssen math.h (C) oder cmath (C ++) einschließen. Denken Sie natürlich daran, dass Sie die Mathematik befolgen müssen, die wir kennen ... nur Zahlen> 0.
Ich musste präziser sein als nur die Position des höchstwertigen Bits, und der von mir verwendete Mikrocontroller hatte keine Mathematikbibliothek. Ich fand heraus, dass nur die Verwendung einer linearen Näherung zwischen 2 ^ n-Werten für positive Ganzzahlwertargumente gut funktioniert. Hier ist der Code:
Alle obigen Antworten sind richtig. Diese Antwort von mir unten kann hilfreich sein, wenn jemand sie braucht. Ich habe diese Anforderung in vielen Fragen gesehen, die wir mit C lösen.
log2 (x) = logy (x) / logy (2)
Wenn Sie jedoch die Sprache C verwenden und das Ergebnis in einer Ganzzahl anzeigen möchten, können Sie Folgendes verwenden:
Konsultieren Sie Ihren Grundkurs Mathematik log n / log 2. Es spielt keine Rolle, ob Sie wählen logoder log10in diesem Fall ist das Teilen durch logdie neue Basis der Trick.
Antworten:
Einfache Mathematik:
log 2 ( x ) = log y ( x ) / log y (2)
Dabei kann y alles sein, was für Standardprotokollfunktionen entweder 10 oder e ist .
quelle
C99 hat
log2
(sowielog2f
undlog2l
für Float und Long Double).quelle
Wenn Sie nach einem ganzzahligen Ergebnis suchen, können Sie einfach das höchste im Wert gesetzte Bit bestimmen und seine Position zurückgeben.
quelle
Integer.highestOneBit(int)
Methode):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
while (i >>= 1) { ++l; }
i>>32
. Da Java jedoch nur 32-Bit-Ints hat, ist dies in Ordnung. Für C / C ++ muss dies berücksichtigt werden.(Multiplikation kann schneller sein als Division)
quelle
quelle
Wie auf http://en.wikipedia.org/wiki/Logarithm angegeben :
Was bedeutet, dass:
quelle
log()
Implementierung nie sieht , wird er dies nicht tun. Mein Fehler.log10()
eine Funktion im C-Standard definiert ist, kann der Compiler sie "speziell" behandeln, einschließlich der Vorberechnung des Ergebnisses, was meiner Meinung nach @Johannes 'Vorschlag war?log10(2)
durch eine Konstante ersetzt.Wenn Sie es schnell machen möchten, können Sie eine Nachschlagetabelle wie in Bit Twiddling Hacks verwenden (nur Ganzzahl log2).
Darüber hinaus sollten Sie einen Blick auf Ihren Compiler builtin Methoden nehmen wie
_BitScanReverse
die könnten schneller sein , weil es vollständig in Hardware berechnet werden.Schauen Sie sich auch mögliche Duplikate an. Wie erstelle ich eine Ganzzahl log2 () in C ++?
quelle
quelle
Grundsätzlich das gleiche wie bei Tomlogic .
quelle
Sie müssen math.h (C) oder cmath (C ++) einschließen. Denken Sie natürlich daran, dass Sie die Mathematik befolgen müssen, die wir kennen ... nur Zahlen> 0.
Beispiel:
quelle
Ich musste präziser sein als nur die Position des höchstwertigen Bits, und der von mir verwendete Mikrocontroller hatte keine Mathematikbibliothek. Ich fand heraus, dass nur die Verwendung einer linearen Näherung zwischen 2 ^ n-Werten für positive Ganzzahlwertargumente gut funktioniert. Hier ist der Code:
In meinem Hauptprogramm musste ich N * log2 (N) / 2 mit einem ganzzahligen Ergebnis berechnen:
temp = (((uint32_t) N) * approx_log_base_2_N_times_256) / 512;
und alle 16-Bit-Werte waren nie um mehr als 2% niedriger
quelle
Alle obigen Antworten sind richtig. Diese Antwort von mir unten kann hilfreich sein, wenn jemand sie braucht. Ich habe diese Anforderung in vielen Fragen gesehen, die wir mit C lösen.
log2 (x) = logy (x) / logy (2)
Wenn Sie jedoch die Sprache C verwenden und das Ergebnis in einer Ganzzahl anzeigen möchten, können Sie Folgendes verwenden:
Hoffe das hilft.
quelle
Konsultieren Sie Ihren Grundkurs Mathematik
log n / log 2
. Es spielt keine Rolle, ob Sie wählenlog
oderlog10
in diesem Fall ist das Teilen durchlog
die neue Basis der Trick.quelle
Verbesserte Version von Ustaman Sangat
quelle