如何在C / C ++中编写日志基础(2)


98

有什么办法可以写log(base 2)函数?

C语言有2个内置函数->>

1。log以e为底。

2。log10 10为基数;

但是我需要以2为底的对数函数。该如何计算。


1
对于眼球计算,以2为底的对数接近等于以10为底的对数加上自然对数。显然,最好在程序中编写一个更准确(更快)的版本。
David Thornley,2010年

对于整数,你可以循环右位位移和停止达到0时,循环次数是日志的近似值
巴西莱Starynkevitch

Answers:


198

简单的数学:

    log 2x)= log yx)/ log y(2)

其中y可以是任何值,对于标准日志函数,其值为10或e



53

如果要查找积分结果,则只需确定值中设置的最高位并返回其位置即可。


27
还有一种不错的位旋转方法(取自Java Integer.highestOneBit(int)方法):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey 2010年

38
...或while (i >>= 1) { ++l; }
Lee Daniel Crocker

2
@Joey假设整数是32位宽,那会起作用,不是吗?对于64位,它将有一个额外的i>>32。但是由于Java只有32位整数,所以很好。对于C / C ++,需要考虑这一点。
Zoso

43
#define M_LOG2E 1.44269504088896340736 // log2(e)

inline long double log2(const long double x){
    return log(x) * M_LOG2E;
}

(乘法可能快于除法)


1
只是想澄清一下-使用日志转换规则+ log_2(e)= 1 / log_e(2)的事实->我们得到了结果
Guy L


9

http://en.wikipedia.org/wiki/Logarithm所述

logb(x) = logk(x) / logk(b)

意思就是:

log2(x) = log10(x) / log10(2)

11
请注意,您可以预先计算log10(2)以提高性能。
corsiKa 2010年

@Johannes:我怀疑编译器会预先计算log10(2)。编译器不知道log10每次都会返回相同的值。就编译器所知,log10(2)可能在连续调用中返回不同的值。
abelenky 2010年

@abelenky:好的,我收回了。由于编译器永远不会看到实现的源代码,log()因此不会这样做。我的错。
乔伊

3
@abelenky:由于log10()C标准中定义了一个函数,因此编译器可以自由地“特殊地”对待它,包括预计算结果,我相信这是@Johannes的建议?
caf 2010年

1
@CarlNorum:我刚刚检查过,gcc 4.7至少替换log10(2)为一个常量。
caf

8

如果要使其快速,可以使用“ Bit Twiddling Hacks”中的查找表(仅适用于整数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];

此外,你应该看看你的编译器内置的方法,如_BitScanReverse可能会更快,因为它可以在硬件完全计算。

还看一下可能的重复项如何在C ++中执行整数log2()?


为什么最后要进行乘法和表查找?您不可以做(v + 1)取整到下一个2的幂吗?然后,你可以通过右一个回合下来转移到的2下一个动力
Safayet艾哈迈德

@SafayetAhmed请描述如何使用该方法查找数字的log2。我不知道获得这种价值的更简单方法。除了使用上面带有查找表的算法外,还可以使用迭代/递归算法或使用专用/内置硬件进行计算。
bkausbk 2015年

假设32位变量v的位编号为0(LSB)至N(MSB)。假设v的最高有效位为n。说n代表floor(log2(v))是否正确?您是否只对n个给定的v感兴趣?
萨法耶·艾哈迈德

我意识到我所描述的只是给你最接近的2的最低幂,而不是实际的对数。乘法和表查找用于从2的幂到对数。您正在将数字0x07C4ACDD左移一些。您左移的数量取决于2的幂。该数字是这样的,即5位的任何连续序列都是唯一的。(0000 0111 1100 0100 0110 1100 1101 1101)给出序列(00000)(00001)...(11101)。根据您向左移动的距离,可以得到以下5位模式之一。然后查表。非常好。
Safayet Ahmed 2015年

3
log2(x) = log10(x) / log10(2)

支持简单,清晰,并根据OP的给定信息提供代码。
2014年

3
uint16_t log2(uint32_t n) {//but truncated
     if (n==0) throw ...
     uint16_t logValue = -1;
     while (n) {//
         logValue++;
         n >>= 1;
     }
     return logValue;
 }

基本上与tomlogic的相同。


1
此解决方案有很多问题,但是总的来说,如果要避免浮点数,这很好。由于要使用-1初始化一个无符号整数,因此您依靠溢出来工作。可以通过将其初始化为0,然后返回值-1(假设您检查0)来解决此问题。另一个问题是,当n == 0时,您依赖循环停止,应该明确声明。除此之外,如果您想避免浮点数,那就很好了。
瑞安·奎因

2

您必须包括math.h(C)或cmath(C ++)当然,请记住,您必须遵循我们知道的数学方法,只有数字> 0。

例:

#include <iostream>
#include <cmath>
using namespace std;

int main(){
    cout<<log2(number);
}

2

我需要具有更高的精度,即最高有效位的位置,而我使用的微控制器没有数学库。我发现仅对正整数值参数使用2 ^ n个值之间的线性近似效果很好。这是代码:

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));
}

在我的主程序中,我需要计算N * log2(N)/ 2和一个整数结果:

temp =((((uint32_t)N)* rox_log_base_2_N_times_256)/ 512;

并且所有16位值的偏差都不会超过2%


1

以上所有答案都是正确的。如果有人需要,下面的我的回答可能会有帮助。我已经在许多使用C解决的问题中看到了这一要求。

log2 (x) = logy (x) / logy (2)

但是,如果您使用的是C语言,并且希望结果为整数,则可以使用以下代码:

int result = (int)(floor(log(x) / log(2))) + 1;

希望这可以帮助。


0

查阅您的基础数学课程,log n / log 2。无论您选择log还是log10在这种情况下,将log新基数除以即可。


0

Ustaman Sangat所做的改进的版本

static inline uint64_t
log2(uint64_t n)
{
    uint64_t val;
    for (val = 0; n > 1; val++, n >>= 1);

    return val;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.