Pour les calculs du globe oculaire, le logarithme de base 2 est presque égal au logarithme de base 10 plus le logarithme naturel. De toute évidence, il est préférable d'écrire une version plus précise (et plus rapide) dans un programme.
David Thornley
Pour les entiers, vous pouvez effectuer une boucle sur le décalage de bits à droite et vous arrêter lorsque vous atteignez 0. Le nombre de boucles est une approximation du journal
Il existe également une méthode intéressante pour cela (tirée de la Integer.highestOneBit(int)méthode de Java ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey
38
... ouwhile (i >>= 1) { ++l; }
Lee Daniel Crocker
2
@Joey Cela fonctionnerait en supposant que l'entier soit large de 32 bits, non? Pour 64 bits, il y aurait un supplément i>>32. Mais comme Java n'a que des entiers 32 bits, c'est bien. Pour C / C ++, il doit être pris en compte.
Notez que vous pouvez précalculer log10 (2) pour augmenter les performances.
corsiKa
@Johannes: Je doute que le compilateur pré-calcule log10 (2). Le compilateur ne sait pas que log10 renverra la même valeur à chaque fois. Pour tout ce que le compilateur sait, log10 (2) pourrait renvoyer des valeurs différentes lors d'appels successifs.
abelenky
@abelenky: Ok, je reprends ça. Puisque le compilateur ne voit jamais la source de l' log()implémentation, il ne le fera pas. Ma faute.
Joey
3
@abelenky: Puisqu'une log10()fonction est définie dans le standard C, le compilateur est libre de la traiter "spécialement", y compris le précalcul du résultat, ce qui, je crois, était la suggestion de @Johannes?
caf
1
@CarlNorum: Je viens de vérifier, et gcc 4.7 au moins remplace log10(2)par une constante.
caf
8
Si vous voulez le rendre rapide, vous pouvez utiliser une table de recherche comme dans Bit Twiddling Hacks (entiers log2 uniquement).
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];
De plus, vous devriez jeter un œil aux méthodes intégrées de vos compilateurs, comme celle _BitScanReversequi pourrait être plus rapide car elle peut être entièrement calculée en matériel.
Pourquoi la multiplication et la recherche de table à la fin? Ne pourriez-vous pas simplement faire (v + 1) qui arrondirait à la prochaine puissance de deux? Et puis, vous pouvez passer à droite par un pour arrondir à la puissance suivante de 2.
Safayet Ahmed
@SafayetAhmed Veuillez décrire comment vous voulez trouver le log2 d'un nombre avec cette méthode. Je ne connais pas de moyen plus simple d'obtenir cette valeur. En plus d'utiliser l'arithmétique ci-dessus avec la table de recherche, on peut utiliser un algorithme itératif / récursif ou utiliser du matériel dédié / intégré pour faire le calcul.
bkausbk
Supposons que les bits d'une variable de 32 bits v soient numérotés de 0 (LSB) à N (MSB). Supposons que le bit d'ensemble le plus significatif de v soit n. Serait-il correct de dire que n représente le plancher (log2 (v))? N'êtes-vous pas intéressé à trouver simplement n donné v?
Safayet Ahmed
J'ai réalisé que ce que je décrivais vous donnerait simplement la puissance la plus basse la plus proche de 2 et non le logarithme réel. La multiplication et la recherche de table permettent de passer de la puissance de deux au logarithme. Vous déplacez le nombre 0x07C4ACDD vers la gauche d'un certain montant. La quantité de décalage vers la gauche dépendra de la puissance de deux. Le nombre est tel que toute séquence consécutive de 5 bits est unique. (0000 0111 1100 0100 0110 1100 1101 1101) vous donne les séquences (00000) (00001) ... (11101). En fonction de votre décalage vers la gauche, vous obtenez l'un de ces modèles de 5 bits. Puis recherche de table. Très agréable.
Il y a quelques problèmes avec cette solution, mais en général, c'est bien si vous voulez éviter les virgules flottantes. Vous comptez sur le débordement pour que cela fonctionne puisque vous initialisez un entier non signé avec -1. Cela peut être résolu en l'initialisant à 0, puis en renvoyant la valeur - 1, en supposant que vous vérifiez le cas 0, ce que vous faites. L'autre problème est que vous comptez sur l'arrêt de la boucle lorsque n == 0, ce que vous devez indiquer explicitement. À part cela, c'est génial si vous voulez éviter les virgules flottantes.
Rian Quinn
2
Vous devez inclure math.h (C) ou cmath (C ++) Bien sûr, gardez à l'esprit que vous devez suivre les mathématiques que nous connaissons ... seuls les nombres> 0.
J'avais besoin d'avoir plus de précision que la position du bit le plus significatif, et le microcontrôleur que j'utilisais n'avait pas de bibliothèque mathématique. J'ai trouvé que simplement utiliser une approximation linéaire entre 2 ^ n valeurs pour les arguments de valeur entière positive fonctionnait bien. Voici le code:
Toutes les réponses ci-dessus sont correctes. Cette réponse ci-dessous peut être utile si quelqu'un en a besoin. J'ai vu cette exigence dans de nombreuses questions que nous résolvons en utilisant C.
log2 (x) = logy (x) / logy (2)
Cependant, si vous utilisez le langage C et que vous voulez que le résultat soit un entier, vous pouvez utiliser ce qui suit:
Consultez vos cours de mathématiques de base, log n / log 2. Peu importe que vous choisissiez logou log10dans ce cas, diviser par logla nouvelle base fait l'affaire.
Réponses:
Mathématiques simples:
log 2 ( x ) = log y ( x ) / log y (2)
où y peut être n'importe quoi, ce qui pour les fonctions de journal standard est soit 10, soit e .
la source
C99 a
log2
(ainsi quelog2f
etlog2l
pour float et long double).la source
Si vous recherchez un résultat intégral, vous pouvez simplement déterminer le bit le plus élevé défini dans la valeur et renvoyer sa position.
la source
Integer.highestOneBit(int)
méthode de Java ):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
. Mais comme Java n'a que des entiers 32 bits, c'est bien. Pour C / C ++, il doit être pris en compte.(la multiplication peut être plus rapide que la division)
la source
la source
Comme indiqué sur http://en.wikipedia.org/wiki/Logarithm :
Ce qui signifie que:
la source
log()
implémentation, il ne le fera pas. Ma faute.log10()
fonction est définie dans le standard C, le compilateur est libre de la traiter "spécialement", y compris le précalcul du résultat, ce qui, je crois, était la suggestion de @Johannes?log10(2)
par une constante.Si vous voulez le rendre rapide, vous pouvez utiliser une table de recherche comme dans Bit Twiddling Hacks (entiers log2 uniquement).
De plus, vous devriez jeter un œil aux méthodes intégrées de vos compilateurs, comme celle
_BitScanReverse
qui pourrait être plus rapide car elle peut être entièrement calculée en matériel.Jetez également un œil aux doublons possibles Comment faire un entier log2 () en C ++?
la source
la source
Fondamentalement, le même que celui de tomlogic .
la source
Vous devez inclure math.h (C) ou cmath (C ++) Bien sûr, gardez à l'esprit que vous devez suivre les mathématiques que nous connaissons ... seuls les nombres> 0.
Exemple:
la source
J'avais besoin d'avoir plus de précision que la position du bit le plus significatif, et le microcontrôleur que j'utilisais n'avait pas de bibliothèque mathématique. J'ai trouvé que simplement utiliser une approximation linéaire entre 2 ^ n valeurs pour les arguments de valeur entière positive fonctionnait bien. Voici le code:
Dans mon programme principal, j'avais besoin de calculer N * log2 (N) / 2 avec un résultat entier:
temp = (((uint32_t) N) * approx_log_base_2_N_times_256) / 512;
et toutes les valeurs 16 bits n'ont jamais été décalées de plus de 2%
la source
Toutes les réponses ci-dessus sont correctes. Cette réponse ci-dessous peut être utile si quelqu'un en a besoin. J'ai vu cette exigence dans de nombreuses questions que nous résolvons en utilisant C.
log2 (x) = logy (x) / logy (2)
Cependant, si vous utilisez le langage C et que vous voulez que le résultat soit un entier, vous pouvez utiliser ce qui suit:
J'espère que cela t'aides.
la source
Consultez vos cours de mathématiques de base,
log n / log 2
. Peu importe que vous choisissiezlog
oulog10
dans ce cas, diviser parlog
la nouvelle base fait l'affaire.la source
Version améliorée de ce qu'a fait Ustaman Sangat
la source