Para los cálculos del globo ocular, el logaritmo en base 2 es casi igual al logaritmo en base 10 más el logaritmo natural. Obviamente, es mejor escribir una versión más precisa (y más rápida) en un programa.
David Thornley
Para números enteros, puede hacer un bucle en el desplazamiento de bits a la derecha y detenerse cuando llegue a 0. El conteo del bucle es una aproximación del registro
También hay un buen método de juego de bits para esto (tomado del Integer.highestOneBit(int)método de Java ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey
38
... owhile (i >>= 1) { ++l; }
Lee Daniel Crocker
2
@Joey Eso funcionaría asumiendo que el entero tiene 32 bits de ancho, ¿no? Para 64 bits tendría un extra i>>32. Pero como Java solo tiene entradas de 32 bits, está bien. Para C / C ++, debe tenerse en cuenta.
Tenga en cuenta que puede calcular previamente log10 (2) para aumentar el rendimiento.
corsiKa
@Johannes: Dudo que el compilador precalcule log10 (2). El compilador no sabe que log10 devolverá el mismo valor cada vez. Por lo que sabe el compilador, log10 (2) podría devolver valores diferentes en llamadas sucesivas.
abelenky
@abelenky: Ok, lo retiro. Dado que el compilador nunca ve la fuente de la log()implementación, no lo hará. Culpa mía.
Joey
3
@abelenky: Dado que log10()es una función definida en el estándar C, el compilador es libre de tratarla "especialmente", incluyendo precalcular el resultado, que creo que fue la sugerencia de @Johannes.
caf
1
@CarlNorum: Acabo de verificar, y gcc 4.7 al menos reemplaza log10(2)con una constante.
caf
8
Si desea hacerlo rápido, puede usar una tabla de búsqueda como en Bit Twiddling Hacks (solo integer 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];
Además, debe echar un vistazo a los métodos incorporados de sus compiladores, como _BitScanReversecuál podría ser más rápido porque puede calcularse completamente en hardware.
¿Por qué la tabla de multiplicar y buscar al final? ¿No podrías simplemente hacer (v + 1) que redondearía a la siguiente potencia de dos? Y luego, podría cambiar uno a la derecha para redondear hacia abajo a la siguiente potencia de 2.
Safayet Ahmed
@SafayetAhmed Describe cómo quieres encontrar el log2 de un número con ese método. No conozco una forma más fácil de obtener ese valor. Además de usar la aritmética anterior con la tabla de búsqueda, se puede usar un algoritmo iterativo / recursivo o usar hardware dedicado / incorporado para hacer el cálculo.
bkausbk
Digamos que los bits de una variable v de 32 bits están numerados del 0 (LSB) al N (MSB). Digamos que el bit de conjunto más significativo de v es n. ¿Sería correcto decir que n representa piso (log2 (v))? ¿No está interesado en encontrar n dado v?
Safayet Ahmed
Me di cuenta de que lo que describí le daría la potencia más baja más cercana de 2 y no el logaritmo real. La multiplicación y la búsqueda de tablas son para ir de la potencia de dos al logaritmo. Está desplazando el número 0x07C4ACDD a la izquierda en cierta cantidad. La cantidad que mueva a la izquierda dependerá de la potencia de dos. El número es tal que cualquier secuencia consecutiva de 5 bits es única. (0000 0111 1100 0100 0110 1100 1101 1101) le da las secuencias (00000) (00001) ... (11101). Dependiendo de qué tan a la izquierda se desplace, obtendrá uno de estos patrones de 5 bits. Luego búsqueda de tabla. Muy agradable.
Hay un par de cosas que no funcionan con esta solución, pero en general, esto es bueno si desea evitar los puntos flotantes. Está confiando en el desbordamiento para que esto funcione, ya que está inicializando un entero sin signo con -1. Esto podría solucionarse inicializándolo a 0 y luego devolviendo el valor - 1, asumiendo que verifica el caso 0, lo cual hace. El otro problema es que confía en que el bucle se detiene cuando n == 0, lo que debe indicar explícitamente. Aparte de eso, esto es genial si desea evitar los puntos flotantes.
Rian Quinn
2
Tienes que incluir math.h (C) o cmath (C ++) Por supuesto, ten en cuenta que tienes que seguir las matemáticas que conocemos ... solo números> 0.
Necesitaba tener más precisión que solo la posición del bit más significativo, y el microcontrolador que estaba usando no tenía biblioteca matemática. Descubrí que solo usar una aproximación lineal entre 2 ^ n valores para argumentos de valor entero positivo funcionaba bien. Aquí está el código:
Todas las respuestas anteriores son correctas. Esta respuesta mía a continuación puede ser útil si alguien la necesita. He visto este requisito en muchas preguntas que estamos resolviendo usando C.
log2 (x) = logy (x) / logy (2)
Sin embargo, si está utilizando lenguaje C y desea que el resultado sea un número entero, puede utilizar lo siguiente:
Consultar a las matemáticas básicas supuesto, log n / log 2. No importa si eliges logo, log10en este caso, dividir por el logde la nueva base funciona.
Respuestas:
Matemáticas simples:
log 2 ( x ) = log y ( x ) / log y (2)
donde y puede ser cualquier cosa, que para las funciones de registro estándar es 10 o e .
fuente
C99 tiene
log2
(así comolog2f
ylog2l
para flotador y doble largo).fuente
Si está buscando un resultado integral, puede simplemente determinar el conjunto de bits más alto en el valor y devolver su posición.
fuente
Integer.highestOneBit(int)
método 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
. Pero como Java solo tiene entradas de 32 bits, está bien. Para C / C ++, debe tenerse en cuenta.(la multiplicación puede ser más rápida que la división)
fuente
fuente
Como se indica en http://en.wikipedia.org/wiki/Logarithm :
Lo que significa que:
fuente
log()
implementación, no lo hará. Culpa mía.log10()
es una función definida en el estándar C, el compilador es libre de tratarla "especialmente", incluyendo precalcular el resultado, que creo que fue la sugerencia de @Johannes.log10(2)
con una constante.Si desea hacerlo rápido, puede usar una tabla de búsqueda como en Bit Twiddling Hacks (solo integer log2).
Además, debe echar un vistazo a los métodos incorporados de sus compiladores, como
_BitScanReverse
cuál podría ser más rápido porque puede calcularse completamente en hardware.Eche un vistazo también a los posibles duplicados ¿Cómo hacer un log2 () entero en C ++?
fuente
fuente
Básicamente lo mismo que el de tomlogic .
fuente
Tienes que incluir math.h (C) o cmath (C ++) Por supuesto, ten en cuenta que tienes que seguir las matemáticas que conocemos ... solo números> 0.
Ejemplo:
fuente
Necesitaba tener más precisión que solo la posición del bit más significativo, y el microcontrolador que estaba usando no tenía biblioteca matemática. Descubrí que solo usar una aproximación lineal entre 2 ^ n valores para argumentos de valor entero positivo funcionaba bien. Aquí está el código:
En mi programa principal, necesitaba calcular N * log2 (N) / 2 con un resultado entero:
temp = (((uint32_t) N) * approx_log_base_2_N_times_256) / 512;
y los valores de 16 bits nunca se desviaron más del 2%
fuente
Todas las respuestas anteriores son correctas. Esta respuesta mía a continuación puede ser útil si alguien la necesita. He visto este requisito en muchas preguntas que estamos resolviendo usando C.
log2 (x) = logy (x) / logy (2)
Sin embargo, si está utilizando lenguaje C y desea que el resultado sea un número entero, puede utilizar lo siguiente:
Espero que esto ayude.
fuente
Consultar a las matemáticas básicas supuesto,
log n / log 2
. No importa si eligeslog
o,log10
en este caso, dividir por ellog
de la nueva base funciona.fuente
Versión mejorada de lo que hizo Ustaman Sangat
fuente