用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