按位运算产生 Python 中的 2 的幂

Bitwise operations to produce power of two in Python

在纯音调理论中,一种音乐理论,音符之间的间隔用有理数表示。以 2:1 比率将频率加倍可将其提高一个八度,而 1:1 比率则没有变化;齐声。因此,如果我有一个大于八度或小于同音(下降)的音程 n,'justify' 就很有用。也就是说,要使 1 ≤ n ≤ 2。我在 Python 中使用以下函数执行此操作:

def justify(n):
    return n / 2 ** floor( log(n,2) )

实际的功能涉及到分数库,但这可以用浮点数和整数来完成工作。对数计算 2 n 的幂次方,然后 floor 将其向下舍入,以便得到的除数是 n 以下最接近的 2 次幂。我也试过这个:

def justify(n):
    return n / int( '1'.ljust( len( bin(n) ) - 2, '0' ), 2 )

这个只是取二进制表示的长度并以此为基础补零。当然,这只适用于整数。我想知道是否有任何方法可以通过按位运算来执行此操作。二进制文件似乎很适合 2 操作的强大功能。至少,我希望看到一种用按位替换 2 ** floor( log(n,2) ) 的方法。如果能处理浮点数加分,但我知道那更复杂。

仅对于整数,您可以使用以下稍微曲折的方式到达那里:

def justify(n):
    return n / 1<<(n.bit_length()-1)

我不知道在没有进行重要测试的情况下它是否更快,但使用 timeit 进行的快速测试表明它比您的第一个代码段快两倍。

但是,将 n 转换为分子中的浮点数(以获得浮点数 return)会将其减慢到与原始速度相同的速度。

def justify(n):
    return float(n) / 1<<(n.bit_length()-1)

bit_length 给出表示 abs(x) 所需的最少位数,这实际上比您计算所需的位数多一位。

我预计 log(n,2) 会在基础中针对 2 的幂进行大量优化 - 它是用 C 实现的。所以你将很难击败它。

可能将分母更改为 1<<int(log(n,2)) 可能会给您带来比 2** 方法更好的性能.. 它似乎比

快 30%
def justify(n):
    return float(n) / (1<<int(log(n,2)))

完全可以用位运算符来完成:

def justify_bitwise(n):
   int_n = int(abs(n))
   p = 0
   while int_n != 1:
       p += 1
       int_n >>= 1

   return float(n) / (1<<p)

但是 timeit 计时为 2.16 微秒。比使用 bit_length

慢一个数量级

math.frexp(x),正如 Mark Dickinson 在问题评论中指出的那样,是要走的路:

def justify(n):
    return 2*frexp(n)[0]

它适用于浮点数和整数。