2016-12-18 7 views
3

11 비트 정수의 압축 된 스트림을 나타내는 bytes 객체 또는 bytearray 객체가 있습니다. (편집 : 스트림은 패딩없이 11 비트 빅 엔디안 정수입니다.)16 비트 정수의 배열에 11 비트 정수를 포함하는 bytearray 캐스팅

이것을 16 비트 정수 스트림으로 복사하는 효율적인 방법이 있습니까? 또는 다른 정수 유형?

나는 ctypes가 비트 필드를 지원한다는 것을 알고 있지만 이것이 나를 전혀 도움이되는지 확신 할 수 없다.

다른 용도로 이미 비트 피딩을하는 표준 라이브러리의 일부를 "남용"할 수 있습니까?

cython에 의존해야한다면 가변 비트 길이를 처리 할 수있는 좋은 구현이 있습니까? 나는. 11 비트 입력뿐만 아니라 12, 13 등을 위해?


편집 : PM2 링의 답변에 따라 순수 파이썬 솔루션

def unpackIntegers(data, num_points, bit_len): 
    """Unpacks an array of integers of arbitrary bit-length into a 
    system-word aligned array of integers""" 
    # TODO: deal with native integer types separately for speedups 
    mask = (1 << bit_len) - 1 

    unpacked_bit_len = 2 ** ceil(log(bit_len, 2)) 
    unpacked_byte_len = ceil(unpacked_bit_len/8) 
    unpacked_array = bytearray(num_points * unpacked_byte_len) 
    unpacked = memoryview(unpacked_array).cast(
     FORMAT_CODES[unpacked_byte_len]) 

    num_blocks = num_points // 8 

    # Note: zipping generators is faster than calculating offsets 
    #  from a block count 
    for idx1_start, idx1_stop, idx2_start, idx2_stop in zip(
      range(0, num_blocks*bit_len, bit_len), 
      range(bit_len, (num_blocks+1)*bit_len, bit_len), 
      range(7, num_points, 8), 
      range(-1, num_points-8, 8), 
      ): 
     n = int.from_bytes(data[idx1_start:idx1_stop], 'big') 
     for i in range(idx2_start, idx2_stop, -1): 
      unpacked[i] = n & mask 
      n >>= bit_len 
    # process left-over part (missing from PM2 Ring's answer) 
    else: 
     points_left = num_points % 8 
     bits_left = points_left * bit_len 
     bytes_left = len(data)-num_blocks*bit_len 
     num_unused_bits = bytes_left * 8 - bits_left 

     n = int.from_bytes(data[num_blocks*bit_len:], 'big') 
     n >>= num_unused_bits 
     for i in range(num_points-1, num_points-points_left-1, -1): 
      unpacked[i] = n & mask 
      n >>= bit_len 
    return unpacked 

답변

2

가 제 3 자 라이브러리와 함께이 작업을 수행 할 수있는보다 효율적인 방법이 될 수 있지만, 여기 한 가지 방법입니다 수 있습니다 표준 파이썬.

unpack 생성자는 data 인수를 청크로 반복하며, data은 바이트를 생성하는 반복 가능한 모든 반복자 일 수 있습니다. 11 비트 데이터의 압축을 풀려면 11 바이트의 청크를 읽고, 그 바이트를 단일 정수로 결합한 다음 해당 정수를 8 조각으로 분할하여 각 조각에 해당하는 11 비트의 데이터가 포함되도록합니다.

def unpack(data, bitlen): 
    mask = (1 << bitlen) - 1 
    for chunk in zip(*[iter(data)] * bitlen): 
     n = int.from_bytes(chunk, 'big') 
     a = [] 
     for i in range(8): 
      a.append(n & mask) 
      n >>= bitlen 
     yield from reversed(a) 

# Test 

# 0 to 23 in 11 bit integers, packed into bytes 
data = bytes([ 
    0, 0, 4, 1, 0, 48, 8, 1, 64, 48, 7, 
    1, 0, 36, 5, 0, 176, 24, 3, 64, 112, 15, 
    2, 0, 68, 9, 1, 48, 40, 5, 64, 176, 23, 
]) 

print(list(unpack(data, 11))) 

출력 databitlen는 바이트의 배수를 포함하지 않는 경우는 무시 될 청크 부분에서 끝나는 것

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] 

참고.