用python计算快速日志基2上限

用python计算快速日志基2上限,python,math,logging,binary,Python,Math,Logging,Binary,对于给定的x=2.7中,可以使用整数的.bit\u length()方法: def brute(x): # determine max p such that 2^p <= x p = 0 while 2**p <= x: p += 1 return p-1 def easy(x): return x.bit_length() - 1 您在注释中指定x是整数,但对于任何来到这里的人来说,如果他们的x已经是一个浮点数,那么将非

对于给定的
x<10^15
,快速准确地确定最大整数
p
,以便
2^p适用于我,OSX 10.7上的Python 2.6.5(CPython):

>>> x = 2**50
>>> x
1125899906842624L
>>> p = int(log(x,2))
>>> p
50
>>> 2**p == x
True

它至少在1e9之前的指数上继续工作,到那时它开始花相当长的时间来计算。在你的测试中,
x
p
实际得到了什么?您正在哪个操作系统上运行哪个版本的Python?

您可以尝试numpy提供的
log2
函数,该函数似乎适用于高达2^62的电源:

>>> 2**np.log2(2**50) == 2**50
True
>>> 2**np.log2(2**62) == 2**62
True
除此之外(至少对我而言),由于numpy内部数字类型的限制,它失败了,但这将处理您所说的处理范围内的数据。

关于“大数不精确”,您在这里面临的挑战是浮点表示确实没有您需要的精确(
49.99999993!=50.0
)。一个很好的参考是“”

好消息是C例程的转换非常简单:

def getpos(value):
    if (value == 0):
        return -1
    pos = 0
    if (value & (value - 1)):
        pos = 1
    if (value & 0xFFFFFFFF00000000):
        pos += 32
        value = value >> 32
    if (value & 0x00000000FFFF0000):
        pos += 16
        value = value >> 16
    if (value & 0x000000000000FF00):
        pos += 8
        value = value >> 8
    if (value & 0x00000000000000F0):
        pos += 4
        value = value >> 4
    if (value & 0x000000000000000C):
        pos += 2
        value = value >> 2
    if (value & 0x0000000000000002):
        pos += 1
        value = value >> 1
    return pos
另一种选择是,您可以舍入到最接近的整数,而不是截断:

   log(x,2)
=> 49.999999999999993
   round(log(x,2),1)
=> 50.0

在Python>=2.7中,可以使用整数的
.bit\u length()
方法:

def brute(x):
    # determine max p such that 2^p <= x
    p = 0
    while 2**p <= x:
        p += 1
    return p-1

def easy(x):
    return x.bit_length() - 1

您在注释中指定x是整数,但对于任何来到这里的人来说,如果他们的x已经是一个浮点数,那么将非常快地提取日志基数2:

log2_slow = int(floor(log(x, 2)))
log2_fast = frexp(x)[1]-1
只需抓住并调整指数。更多的“splainin:

  • 下标
    [1]
    是因为frexp()返回一个元组(有效位,指数)
  • 减法
    -1
    说明有效位在[0.5,1.0]范围内。例如,250存储为0.5x251

  • floor()是因为您指定了
    2^pI需要计算2的上限幂(要计算出在给定范围内使用模运算符生成随机数需要多少字节的熵)

    根据粗略的实验,我认为下面的计算给出了最小整数p,使得val<2^p

    它可能是你能得到的最快的,并且只使用按位整数运算

    def log2_approx(val):
        from math import floor
        val = floor(val)
        approx = 0
        while val != 0:
            val &= ~ (1<<approx)
            approx += 1
        return approx
    

    …也许吧。但无论如何,按位运算可以给你一个快速执行的线索。

    这里有一个--你必须单击“运行会话”按钮。我得到49.9999999而不是50.0的p。可能是因为我的电脑是32位的。我不希望32对64位会影响math.log。奇怪。你可能想阅读和的文档。这可以帮助你将C代码翻译成Python。可能类似于你指的是地板而不是天花板?因为p是最大整数,所以它们是ally do mean天花板,就像在
    q==ceil(log(x,2))
    中一样,就像一个老板。我不知道bit_length()函数。谢谢,是的,我碰巧在这个项目中使用了python 3.3:P
    >>> brute(0), brute(2**3-1), brute(2**3)
    (-1, 2, 3)
    >>> easy(0), easy(2**3-1), easy(2**3)
    (-1, 2, 3)
    >>> brute(2**50-1), brute(2**50), brute(2**50+1)
    (49, 50, 50)
    >>> easy(2**50-1), easy(2**50), easy(2**50+1)
    (49, 50, 50)
    >>> 
    >>> all(brute(n) == easy(n) for n in range(10**6))
    True
    >>> nums = (max(2**x+d, 0) for x in range(200) for d in range(-50, 50))
    >>> all(brute(n) == easy(n) for n in nums)
    True
    
    log2_slow = int(floor(log(x, 2)))
    log2_fast = frexp(x)[1]-1
    
    def log2_approx(val):
        from math import floor
        val = floor(val)
        approx = 0
        while val != 0:
            val &= ~ (1<<approx)
            approx += 1
        return approx
    
    log2_approx(n) - 1