Para cálculos do globo ocular, o logaritmo de base 2 é quase igual ao logaritmo de base 10 mais o logaritmo natural. Obviamente, é melhor escrever uma versão mais precisa (e mais rápida) em um programa.
David Thornley
Para inteiros, você pode fazer um loop no bithift direito e parar quando chegar a 0. A contagem do loop é uma aproximação do log
Há também um bom método de ajuste de bits para isso (tirado do Integer.highestOneBit(int)método 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 Isso funcionaria assumindo que o inteiro tem 32 bits de largura, não? Para 64 bits teria um extra i>>32. Mas, como o Java tem apenas ints de 32 bits, tudo bem. Para C / C ++, isso precisa ser considerado.
Observe que você pode pré-calcular o log10 (2) para aumentar o desempenho.
corsiKa
@Johannes: Duvido que o compilador pré-calcule o log10 (2). O compilador não sabe que log10 retornará o mesmo valor todas as vezes. Até onde o compilador sabe, log10 (2) poderia retornar valores diferentes em chamadas sucessivas.
Abelenky
@abelenky: Ok, retiro o que disse. Como o compilador nunca vê o código-fonte da log()implementação, ele não o fará. Foi mal.
Joey
3
@abelenky: Como log10()uma função é definida no padrão C, o compilador está livre para tratá-la "especialmente", incluindo pré-computar o resultado, o que acredito ter sido a sugestão de @Johannes?
caf de
1
@CarlNorum: Acabei de verificar e o gcc 4.7 pelo menos substitui log10(2)por uma constante.
caf
8
Se você quiser torná-lo mais rápido, você pode usar uma tabela de pesquisa como em Bit Twiddling Hacks (log2 inteiro apenas).
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];
Além disso, você deve dar uma olhada nos métodos embutidos do seu compilador, como o _BitScanReversequal pode ser mais rápido porque pode ser inteiramente computado em hardware.
Por que a multiplicação e a consulta à tabela no final? Você não poderia simplesmente fazer (v + 1) que arredondaria para a próxima potência de dois? E então, você pode mudar para a direita em um para arredondar para a próxima potência de 2.
Safayet Ahmed
@SafayetAhmed Descreva como deseja localizar o log2 de um número com esse método. Não conheço uma maneira mais fácil de obter esse valor. Além de usar a aritmética acima com a tabela de pesquisa, pode-se usar um algoritmo iterativo / recursivo ou usar hardware dedicado / embutido para fazer o cálculo.
bkausbk
Digamos que os bits de uma variável de 32 bits v são numerados de 0 (LSB) a N (MSB). Digamos que o conjunto de bits mais significativo de v seja n. Seria correto dizer que n representa floor (log2 (v))? Você não está interessado em apenas encontrar n dado v?
Safayet Ahmed
Percebi que o que descrevi apenas forneceria a potência mais baixa de 2 mais próxima e não o logaritmo real. A multiplicação e a consulta à tabela servem para passar da potência de dois ao logaritmo. Você está mudando o número 0x07C4ACDD deixado por alguma quantia. A quantidade que você desloca para a esquerda dependerá da potência de dois. O número é tal que qualquer sequência consecutiva de 5 bits é única. (0000 0111 1100 0100 0110 1100 1101 1101) fornece as sequências (00000) (00001) ... (11101). Dependendo de quão distante você desloca para a esquerda, você obtém um desses padrões de 5 bits. Em seguida, consulta de tabela. Muito agradável.
Existem algumas coisas erradas com esta solução, mas em geral, isso é bom se você quiser evitar pontos flutuantes. Você está contando com o estouro para que isso funcione, pois está inicializando um inteiro não assinado com -1. Isso poderia ser corrigido inicializando-o com 0 e, em seguida, retornando o valor -1, assumindo que você verifique o caso 0, o que você faz. O outro problema é que você está contando com a parada do loop quando n == 0, o que você deve declarar explicitamente. Fora isso, isso é ótimo se você quiser evitar pontos flutuantes.
Rian Quinn
2
Você tem que incluir math.h (C) ou cmath (C ++). Claro, lembre-se de que você deve seguir a matemática que conhecemos ... apenas números> 0.
Eu precisava ter mais precisão do que apenas a posição do bit mais significativo, e o microcontrolador que estava usando não tinha biblioteca matemática. Descobri que apenas usar uma aproximação linear entre 2 ^ n valores para argumentos de valor inteiro positivo funcionou bem. Aqui está o código:
Todas as respostas acima estão corretas. Esta minha resposta abaixo pode ser útil se alguém precisar dela. Eu vi esse requisito em muitas questões que estamos resolvendo usando C.
log2 (x) = logy (x) / logy (2)
No entanto, se estiver usando a linguagem C e quiser o resultado em número inteiro, você pode usar o seguinte:
Consulte o seu curso de matemática básica log n / log 2,. Não importa se você escolhe logou log10, neste caso, dividir pelo valor logda nova base resolve.
Respostas:
Matemática simples:
log 2 ( x ) = log y ( x ) / log y (2)
onde y pode ser qualquer coisa, que para funções de log padrão é 10 ou e .
fonte
C99 tem
log2
(assim comolog2f
elog2l
para float e long double).fonte
Se você está procurando um resultado integral, pode apenas determinar o bit mais alto definido no valor e retornar sua posição.
fonte
Integer.highestOneBit(int)
método 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
. Mas, como o Java tem apenas ints de 32 bits, tudo bem. Para C / C ++, isso precisa ser considerado.(a multiplicação pode ser mais rápida do que a divisão)
fonte
fonte
Conforme declarado em http://en.wikipedia.org/wiki/Logarithm :
O que significa que:
fonte
log()
implementação, ele não o fará. Foi mal.log10()
uma função é definida no padrão C, o compilador está livre para tratá-la "especialmente", incluindo pré-computar o resultado, o que acredito ter sido a sugestão de @Johannes?log10(2)
por uma constante.Se você quiser torná-lo mais rápido, você pode usar uma tabela de pesquisa como em Bit Twiddling Hacks (log2 inteiro apenas).
Além disso, você deve dar uma olhada nos métodos embutidos do seu compilador, como o
_BitScanReverse
qual pode ser mais rápido porque pode ser inteiramente computado em hardware.Dê uma olhada também nas possíveis duplicatas. Como fazer um log2 () inteiro em C ++?
fonte
fonte
Basicamente o mesmo do tomlogic .
fonte
Você tem que incluir math.h (C) ou cmath (C ++). Claro, lembre-se de que você deve seguir a matemática que conhecemos ... apenas números> 0.
Exemplo:
fonte
Eu precisava ter mais precisão do que apenas a posição do bit mais significativo, e o microcontrolador que estava usando não tinha biblioteca matemática. Descobri que apenas usar uma aproximação linear entre 2 ^ n valores para argumentos de valor inteiro positivo funcionou bem. Aqui está o código:
Em meu programa principal, precisei calcular N * log2 (N) / 2 com um resultado inteiro:
temp = (((uint32_t) N) * approx_log_base_2_N_times_256) / 512;
e todos os valores de 16 bits nunca foram desativados em mais de 2%
fonte
Todas as respostas acima estão corretas. Esta minha resposta abaixo pode ser útil se alguém precisar dela. Eu vi esse requisito em muitas questões que estamos resolvendo usando C.
log2 (x) = logy (x) / logy (2)
No entanto, se estiver usando a linguagem C e quiser o resultado em número inteiro, você pode usar o seguinte:
Espero que isto ajude.
fonte
Consulte o seu curso de matemática básica
log n / log 2
,. Não importa se você escolhelog
oulog10
, neste caso, dividir pelo valorlog
da nova base resolve.fonte
Versão aprimorada do que Ustaman Sangat fez
fonte