

お世話になります。

【 使用言語 】

Python3

【 したいこと 】

今、Byte（8bit）長の配列（リスト）変数 a[32] の  
32Byte全体分 を 256bit列 と考えた場合、  
このビット列全体を Right Shift させたいのですが、  
どうようにすればできるのでしょうか？

Python または numpy または scipy で  
一発変換できる関数が存在するのでしょうか？

宜しくお願い致します。


CC BY-SA 3.0
2017-04-20T07:20:28.587
34157
2017-09-07T07:42:08.023
20579
question
python
Python で 32個の１次元配列全体を ビットシフトさせたい。


以下は 5 ビット右シフトする例です。バイト列を 256 ビット長の整数値に変換してシフトした後、8 ビット単位で整数値に戻しています。

[code]

    >>> import re
    
    >>> lst = list(iter(b'@12 Hello World, Good bye World.'))
    >>> lst
    [64, 49, 50, ..., 108, 100, 46]
    >>> len(lst)
    32
    
    >>> list(map(lambda x: int(x, 2),
         re.findall('.{8}',
           format(sum([int(x)*(2**(8*(len(lst)-i-1))) for i, x in enumerate(lst)])>>5, '0256b')
         )))
    [2, 1, 137, ..., 147, 99, 33]
    
[/code]

これでは分かりにくいかと思いますので、例えば 32 ビット(4 バイト)右シフトしてみます。

[code]

    >>> shifted = list(map(lambda x: int(x, 2),
         re.findall('.{8}',
           format(sum([int(x)*(2**(8*(len(lst)-i-1))) for i, x in enumerate(lst)])>>32, '0256b')
         )))
    
    >>> str(''.join(map(chr, shifted)))
    '\x00\x00\x00\x00@12 Hello World, Good bye Wo'
    
[/code]


CC BY-SA 3.0
2017-04-20T12:01:30.723
34163
2017-04-20T12:17:56.743
2017-04-20T12:17:56.743
34157
answer


int8 が32個集まり256bitのintとなっている、という視点で実装してみました。  
例では32bit分だけですが、任意の長さまで拡張可能です

[code]

    # -*- coding: utf-8 -*-
    
    import numpy as np
    
    DIGITS = 8
    
    def print_bits(bits):
        for bit in bits:
            print np.binary_repr(bit).zfill(DIGITS)
    
    # 右シフトして消滅するビットを得る(左詰め)
    def get_underflow_bits(bits, n):
        return np.bitwise_and(2 ** DIGITS - 1, np.left_shift(bits, DIGITS - n))
    
    # 右シフトした結果、隣の配列に移動したbitだけを返す
    def get_underflows(bits, n):
        return np.insert(get_underflow_bits(bits, n), 0, 0)[:-1]
    
    # 単純に右シフトした結果と、桁移動したもののORを取る
    def right_shift(bits, n):
        return np.bitwise_or(np.right_shift(bits, n), get_underflows(bits, n))
    
    sample = [255, 0, 255, 0]
    print_bits(right_shift(sample, 3))
    
[/code]


CC BY-SA 3.0
2017-04-20T12:55:31.403
34166
2017-04-20T12:55:31.403
15705
34157
answer


一度大きな整数を作ってから右にシフトして配列に戻す実装です。ご参考になれば。

[code]

    from functools import reduce
    
    
    def shift(a, bits):
        D = 8
        n = len(a)
        value = reduce(lambda x, y: x | y, (e << (D * (n - 1 - i)) for i, e in enumerate(a)))
        value >>= bits
        s = '{:0{}b}'.format(value, len(a) * D)
        return [int(s[i * D:(i + 1) * D], 2) for i in range(n)]
    
    
    a = [0b11111111, 0b01010101, 0b00001111]
    print(' '.join('{:08b}'.format(x) for x in shift(a, 0)))  # 11111111 01010101 00001111
    print(' '.join('{:08b}'.format(x) for x in shift(a, 1)))  # 01111111 10101010 10000111
    print(' '.join('{:08b}'.format(x) for x in shift(a, 2)))  # 00111111 11010101 01000011
    print(' '.join('{:08b}'.format(x) for x in shift(a, 3)))  # 00011111 11101010 10100001
    print(' '.join('{:08b}'.format(x) for x in shift(a, 4)))  # 00001111 11110101 01010000
    print(' '.join('{:08b}'.format(x) for x in shift(a, 5)))  # 00000111 11111010 10101000
    print(' '.join('{:08b}'.format(x) for x in shift(a, 6)))  # 00000011 11111101 01010100
    print(' '.join('{:08b}'.format(x) for x in shift(a, 7)))  # 00000001 11111110 10101010
    print(' '.join('{:08b}'.format(x) for x in shift(a, 8)))  # 00000000 11111111 01010101
    print(' '.join('{:08b}'.format(x) for x in shift(a, 9)))  # 00000000 01111111 10101010
    print(' '.join('{:08b}'.format(x) for x in shift(a, 10)))  # 00000000 00111111 11010101
    
[/code]


CC BY-SA 3.0
2017-04-21T06:09:02.410
34180
2017-04-21T06:09:02.410
22692
34157
answer