Czy istnieje sposób na zapisanie funkcji dziennika (podstawa 2)?
Język C ma 2 wbudowane funkcje - >>
1. log
która jest podstawą e.
2. log10
podstawa 10;
Ale potrzebuję funkcji dziennika o podstawie 2. Jak to obliczyć.
Czy istnieje sposób na zapisanie funkcji dziennika (podstawa 2)?
Język C ma 2 wbudowane funkcje - >>
1. log
która jest podstawą e.
2. log10
podstawa 10;
Ale potrzebuję funkcji dziennika o podstawie 2. Jak to obliczyć.
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 .
C99 ma log2
(jak również log2f
i log2l
dla float i long double).
Jeśli szukasz wyniku całkowego, możesz po prostu określić najwyższy bit ustawiony w wartości i zwrócić jego pozycję.
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ę.
#define M_LOG2E 1.44269504088896340736 // log2(e)
inline long double log2(const long double x){
return log(x) * M_LOG2E;
}
(mnożenie może być szybsze niż dzielenie)
Jak podano na http://en.wikipedia.org/wiki/Logarithm :
logb(x) = logk(x) / logk(b)
Co oznacza że:
log2(x) = log10(x) / log10(2)
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).
uint32_t v; // find the log base 2 of 32-bit v
int r; // result goes here
static const int MultiplyDeBruijnBitPosition[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, _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 ++?
uint16_t log2(uint32_t n) {//but truncated
if (n==0) throw ...
uint16_t logValue = -1;
while (n) {//
logValue++;
n >>= 1;
}
return logValue;
}
Zasadniczo to samo, co tomlogic .
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:
#include <iostream>
#include <cmath>
using namespace std;
int main(){
cout<<log2(number);
}
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:
uint16_t approx_log_base_2_N_times_256(uint16_t n)
{
uint16_t msb_only = 0x8000;
uint16_t exp = 15;
if (n == 0)
return (-1);
while ((n & msb_only) == 0) {
msb_only >>= 1;
exp--;
}
return (((uint16_t)((((uint32_t) (n ^ msb_only)) << 8) / msb_only)) | (exp << 8));
}
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%
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:
int result = (int)(floor(log(x) / log(2))) + 1;
Mam nadzieję że to pomoże.
Ulepszona wersja tego, co zrobił Ustaman Sangat
static inline uint64_t
log2(uint64_t n)
{
uint64_t val;
for (val = 0; n > 1; val++, n >>= 1);
return val;
}