Numpy int 位长度

问题描述 投票:0回答:4

我想找到以二进制表示无符号 numpy 整数(或整数数组中的每个元素)所需的位数,就像 python 的

int.bit_length()
所做的那样,但 numpy 似乎没有等效的函数。

例如:

>>> int(0b1000).bit_length()
4
>>> np.uint8(0b1000).bit_length()
AttributeError: 'numpy.uint8' object has no attribute 'bit_length'

谁能帮我找到正确的函数?我当前的方法是将每个数组元素转换为 python int 来查找位长度,为了速度和清晰度,这似乎是一个糟糕的选择:

np.vectorize(lambda np_int: int(np_int).bit_length())
python numpy
4个回答
1
投票

你可以取数组 log2 的上限。

import numpy as np

x = np.random.randint(0, 100, size=30)
x
# returns:
array([92,  7, 53, 24, 85, 53, 78, 52, 99, 91, 79, 40, 82, 34, 18, 26, 20,
        7, 47, 38, 78, 50, 15, 12, 54,  3, 91, 82, 22, 90])

np.ceil(np.log2(x)).astype(int)
# returns:
array([7, 3, 6, 5, 7, 6, 7, 6, 7, 7, 7, 6, 7, 6, 5, 5, 5, 3, 6, 6, 7, 6,
       4, 4, 6, 2, 7, 7, 5, 7])

0
投票

试试这个:

np.uint8(0b1000).nbytes*8

最后的 *8 只是每个字节的位数


0
投票

经典的位操作黑客算法应该很容易适应 numpy:

https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog

这是 32 位无符号整数的变体:

def bit_length(v):
  r =     (v > 0xFFFF) << 4; v >>= r
  shift = (v > 0xFF  ) << 3; v >>= shift; r |= shift
  shift = (v > 0xF   ) << 2; v >>= shift; r |= shift
  shift = (v > 0x3   ) << 1; v >>= shift; r |= shift
  return r | (v >> 1)

考虑到向量化,对于非常大的列表和双精度数默认尾数大小为 2^53 的数字,使用浮点 log2 方法可能会获得更好的性能。 其实并不慢。 Numpy 需要提供 CTZ 或 CLZ 函数,否则这里只发生反前导零或反尾随零。 顺便说一句,浮点 log2 并没有比这些相同的 CPU 类型操作做更多的事情。 所以它可能并不像看起来那么低效。


0
投票

使用

np.frexp(arr)[1]
的速度比
np.ceil(np.log2(x)).astype(int)
快 4 到 6 倍。

请注意,正如@GregoryMorse 上面所指出的,需要一些额外的工作来保证 64 位输入的正确结果(下面的

bit_length3
)。

import numpy as np


def bit_length1(arr):
    # assert arr.max() < (1<<53)
    return np.ceil(np.log2(arr)).astype(int)

    
def bit_length2(arr):
    # assert arr.max() < (1<<53)
    return np.frexp(arr)[1]


def bit_length3(arr):  # 64-bit safe
    _, high_exp = np.frexp(arr >> 32)
    _, low_exp = np.frexp(arr & 0xFFFFFFFF)
    return np.where(high_exp, high_exp + 32, low_exp)

perf results 性能结果,通过 https://perfpy.com/868 对 100,000 个元素的数组进行 10 次迭代。

© www.soinside.com 2019 - 2024. All rights reserved.