W przypadku obliczeń gałki ocznej logarytm o podstawie 2 jest bliski równości logarytmowi o podstawie 10 plus logarytm naturalny. Oczywiście lepiej jest napisać w programie dokładniejszą (i szybszą) wersję.
David Thornley
W przypadku liczb całkowitych można było wykonać pętlę z przesunięciem w prawo i zatrzymać się po osiągnięciu 0. Liczba pętli jest przybliżeniem dziennika
Jest na to również niezła metoda przekręcania bitów (zaczerpnięta z Integer.highestOneBit(int)metody Javy ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey
38
... lubwhile (i >>= 1) { ++l; }
Lee Daniel Crocker
2
@Joey To działałoby przy założeniu, że liczba całkowita ma 32 bity szerokości, nie? W przypadku wersji 64-bitowej miałby dodatkowy i>>32. Ale ponieważ Java ma tylko 32-bitowe inty, jest w porządku. W przypadku C / C ++ należy to wziąć pod uwagę.
Zauważ, że możesz wstępnie obliczyć log10 (2), aby zwiększyć wydajność.
corsiKa
@Johannes: Wątpię, czy kompilator wstępnie obliczy log10 (2). Kompilator nie wie, że log10 za każdym razem zwróci tę samą wartość. Z tego, co wie kompilator, log10 (2) może zwracać różne wartości przy kolejnych wywołaniach.
abelenky
@abelenky: Ok, cofam to. Ponieważ kompilator nigdy nie widzi źródła log()implementacji, nie zrobi tego. Mój błąd.
Joey
3
@abelenky: Skoro log10()funkcja jest zdefiniowana w standardzie C, kompilator może traktować ją „specjalnie”, włączając w to wstępne obliczanie wyniku, co, jak sądzę, było sugestią @Johannes?
kawiarnia
1
@CarlNorum: Właśnie sprawdziłem i gcc 4.7 przynajmniej zastępuje log10(2)stałą.
kawiarnia
8
Jeśli chcesz zrobić to szybko, możesz użyć tabeli odnośników, takiej jak w Bit Twiddling Hacks (tylko liczba całkowita 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];
Ponadto powinieneś przyjrzeć się wbudowanym metodom kompilatorów, takim jak te, _BitScanReversektóre mogą być szybsze, ponieważ mogą być całkowicie obliczone sprzętowo.
Po co mnożenie i wyszukiwanie w tabeli na końcu? Nie mógłbyś po prostu zrobić (v + 1), które zaokrągliłoby w górę do następnej potęgi dwóch? Następnie możesz przesunąć się w prawo o jeden, aby zaokrąglić w dół do następnej potęgi 2.
Safayet Ahmed,
@SafayetAhmed Opisz, jak chcesz znaleźć log2 liczby za pomocą tej metody. Nie znam prostszego sposobu na uzyskanie tej wartości. Oprócz zastosowania powyższej arytmetyki z tablicą przeglądową, można użyć algorytmu iteracyjnego / rekurencyjnego lub użyć dedykowanego / wbudowanego sprzętu do wykonania obliczeń.
bkausbk
Powiedzmy, że bity 32-bitowej zmiennej v są ponumerowane od 0 (LSB) do N (MSB). Powiedzmy, że najbardziej znaczący zestaw bitów v to n. Czy poprawne byłoby stwierdzenie, że n reprezentuje piętro (log2 (v))? Czy nie jesteś zainteresowany znalezieniem n danego v?
Safayet Ahmed
Zdałem sobie sprawę, że to, co opisałem, da ci najbliższą najniższą potęgę 2, a nie rzeczywisty logarytm. Mnożenie i wyszukiwanie w tabeli służą do przechodzenia od potęgi dwójki do logarytmu. Przesuwasz liczbę 0x07C4ACDD w lewo o pewną kwotę. Wielkość przesunięcia w lewo zależy od potęgi dwóch. Liczba jest taka, że każda kolejna sekwencja 5 bitów jest niepowtarzalna. (0000 0111 1100 0100 0110 1100 1101 1101) podaje sekwencje (00000) (00001) ... (11101). W zależności od tego, jak daleko w lewo się przesuniesz, otrzymasz jeden z tych 5-bitowych wzorów. Następnie przeszukaj tabelę. Bardzo dobrze.
Jest kilka rzeczy nie tak z tym rozwiązaniem, ale ogólnie jest to przyjemne, jeśli chcesz uniknąć zmiennoprzecinkowych. Aby to zadziałało, polegasz na przepełnieniu, ponieważ inicjujesz liczbę całkowitą bez znaku z -1. Można to naprawić, inicjując go na 0, a następnie zwracając wartość - 1, zakładając, że sprawdzasz przypadek 0, co robisz. Inną kwestią jest to, że polegasz na zatrzymywaniu pętli, gdy n == 0, co powinieneś wyraźnie określić. Poza tym jest to świetne, jeśli chcesz uniknąć zmiennoprzecinkowych.
Rian Quinn
2
Musisz uwzględnić math.h (C) lub cmath (C ++). Oczywiście pamiętaj, że musisz postępować zgodnie z matematyką, którą znamy ... tylko liczby> 0.
Musiałem mieć większą precyzję, niż tylko położenie najbardziej znaczącego bitu, a mikrokontroler, którego używałem, nie miał biblioteki matematycznej. Okazało się, że samo użycie liniowego przybliżenia między 2 ^ n wartościami dodatnich wartości całkowitych działa dobrze. Oto kod:
Wszystkie powyższe odpowiedzi są prawidłowe. Poniższa odpowiedź może być pomocna, jeśli ktoś jej potrzebuje. Widziałem ten wymóg w wielu pytaniach, które rozwiązujemy za pomocą C.
log2 (x) = logy (x) / logy (2)
Jeśli jednak używasz języka C i chcesz, aby wynik był liczbą całkowitą, możesz użyć następującego:
Konsultować swoje podstawowe matematyki Oczywiście log n / log 2. Nie ma znaczenia, czy wybierzesz, logczy log10w tym przypadku podzielenie przez lognową bazę załatwia sprawę .
Odpowiedzi:
Prosta matematyka:
log 2 ( x ) = log y ( x ) / log y (2)
gdzie y może być dowolną wartością, co dla standardowych funkcji dziennika wynosi 10 lub e .
źródło
C99 ma
log2
(jak równieżlog2f
ilog2l
dla float i long double).źródło
Jeśli szukasz wyniku całkowego, możesz po prostu określić najwyższy bit ustawiony w wartości i zwrócić jego pozycję.
źródło
Integer.highestOneBit(int)
metody Javy ):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
. Ale ponieważ Java ma tylko 32-bitowe inty, jest w porządku. W przypadku C / C ++ należy to wziąć pod uwagę.(mnożenie może być szybsze niż dzielenie)
źródło
źródło
Jak podano na http://en.wikipedia.org/wiki/Logarithm :
Co oznacza że:
źródło
log()
implementacji, nie zrobi tego. Mój błąd.log10()
funkcja jest zdefiniowana w standardzie C, kompilator może traktować ją „specjalnie”, włączając w to wstępne obliczanie wyniku, co, jak sądzę, było sugestią @Johannes?log10(2)
stałą.Jeśli chcesz zrobić to szybko, możesz użyć tabeli odnośników, takiej jak w Bit Twiddling Hacks (tylko liczba całkowita log2).
Ponadto powinieneś przyjrzeć się wbudowanym metodom kompilatorów, takim jak te,
_BitScanReverse
które mogą być szybsze, ponieważ mogą być całkowicie obliczone sprzętowo.Przyjrzyj się również możliwemu duplikatowi. Jak zrobić liczbę całkowitą log2 () w C ++?
źródło
źródło
Zasadniczo to samo, co tomlogic .
źródło
Musisz uwzględnić math.h (C) lub cmath (C ++). Oczywiście pamiętaj, że musisz postępować zgodnie z matematyką, którą znamy ... tylko liczby> 0.
Przykład:
źródło
Musiałem mieć większą precyzję, niż tylko położenie najbardziej znaczącego bitu, a mikrokontroler, którego używałem, nie miał biblioteki matematycznej. Okazało się, że samo użycie liniowego przybliżenia między 2 ^ n wartościami dodatnich wartości całkowitych działa dobrze. Oto kod:
W moim głównym programie musiałem obliczyć N * log2 (N) / 2 z wynikiem w postaci liczby całkowitej:
temp = (((uint32_t) N) * approx_log_base_2_N_times_256) / 512;
a wszystkie wartości 16-bitowe nigdy nie były wyłączone o więcej niż 2%
źródło
Wszystkie powyższe odpowiedzi są prawidłowe. Poniższa odpowiedź może być pomocna, jeśli ktoś jej potrzebuje. Widziałem ten wymóg w wielu pytaniach, które rozwiązujemy za pomocą C.
log2 (x) = logy (x) / logy (2)
Jeśli jednak używasz języka C i chcesz, aby wynik był liczbą całkowitą, możesz użyć następującego:
Mam nadzieję że to pomoże.
źródło
Konsultować swoje podstawowe matematyki Oczywiście
log n / log 2
. Nie ma znaczenia, czy wybierzesz,log
czylog10
w tym przypadku podzielenie przezlog
nową bazę załatwia sprawę .źródło
Ulepszona wersja tego, co zrobił Ustaman Sangat
źródło