2015-09-09 16 views
12

Pythonでは、64ビット整数が与えられています。このIntegerは、いくつかの異なる8ビット整数を取り、それを1つの巨大な64ビット整数にマッシュすることによって作成されました。それらを再び分離するのは私の仕事です。例えば64ビット整数をPythonの8つの別々の1バイト整数に変換する

Source number: 2592701575664680400 
Binary (64 bits): 0010001111111011001000000101100010101010000101101011111000000000 
int 1: 00100011 (35) 
int 2: 11111011 (251) 
int 3: 00100000 (32) 
int 4: 01011000 (88) 
int 5: 10101010 (170) 
int 6: 00010110 (22) 
int 7: 10111110 (190) 
int 8: 00000000 (0) 

それでは、私がやりたいことは、私のソース番号2592701575664680373を取ると、アレイ内の各intは、上記のint型です長さ8の配列を返すです。

私はstructを使用しようとしていましたが、完全に正直であると、documentationを読むと、私がそれを達成する方法を明確にしていません。

+0

あなたは 'divmod()'を試しましたか? – lenz

+0

ダング、あなたは正しい@パドレイクカニンガムです。私は十分に大きな数字をサポートしていない素早く汚れたツールを使用していました。最後の部分を0で表していました。これで 'bin = '{0:064b}'を実行しました。format(source)'あなたが正しいことが分かります。 – JHixson

+0

'n'が奇数で、最後に1がないと私は混乱してしまいました –

答えて

6

Python 2.xでは、struct.packはバイト列を返します。これを整数の配列に変換するのは簡単です。 Pythonで

>>> bytestr = struct.pack('>Q', 2592701575664680400) 
>>> bytestr 
'#\xfb X\xaa\x16\xbd\xd0' 
>>> [ord(b) for b in bytestr] 
[35, 251, 32, 88, 170, 22, 189, 208] 

structモジュールは、典型的には、Cの構造パッキング規則に従ってパックドバイト文字列にPythonオブジェクトから変換するために使用されます。 struct.packは、フォーマット指定子(構造体のバイトのレイアウト方法を記述する文字列)といくつかのPythonデータを取り、それをバイト文字列にパックします。 struct.unpackは逆を行います。フォーマット指定子とバイト文字列をとり、解凍されたデータのタプルをpythonオブジェクトの形式でもう一度返します。

使用されている書式指定子には2つの部分があります。先頭文字は、文字列のエンディアン(バイト順)を指定します。次の文字は、パックまたはアンパックされる構造体のフィールドの型を指定します。したがって、'>Q'はビッグエンディアンとして与えられたデータをパックすることを意味しますunsigned long long。逆の順序でバイトを取得するには、リトルエンディアンの代わりに<を使用できます。

最後の操作は、バイトストリングの文字を繰り返し処理し、ord組み込み関数を使用して、その文字の整数表現を取得するリストの解説です。

最終ノート:Pythonには実際には整数サイズの概念はありません。 2.xでは、intが32ビットに制限され、longが無制限のサイズです。 3.xでは、これらの2つが単一のタイプに統合されました。したがって、この操作では1バイトしか取らない整数を与えることが保証されますが、他の操作で使用する場合は、結果として得られる整数をそのままにしておくことに注意してください。

+0

説明をいただきありがとうございます!これは私の問題を解決するだけでなく、今から 'struct'モジュールを使用する私の能力にもっと自信が持てます。 – JHixson

+0

@JHixsonコードで答えると、説明全体を追加したzstewartに感謝します。 –

2
bn = "0010001111111011001000000101100010101010000101101011111000000000" 

print([int(bn[i:i+8], 2) for i in range(0,len(bn), 8)]) 
[35, 251, 32, 88, 170, 22, 190, 0] 

あなたは、出力が異なるだろうn個のバイナリ表現を使用している場合:

n = 2592701575664680373 
bn = bin(n) 

print([int(bn[i:i+8], 2) for i in range(0,len(bn), 8)]) 
[35, 251, 32, 88, 170, 22, 189, 181] 

いくつかのタイミング:

In [16]: %%timeit             
numbers = list((n >> i) & 0xFF for i in range(0,64,8)) 
list(reversed(numbers)) 
    ....: 
100000 loops, best of 3: 2.97 µs per loop 

In [17]: timeit [(n >> (i * 8)) & 0xFF for i in range(7, -1, -1)] 
1000000 loops, best of 3: 1.73 µs per loop 

In [18]: %%timeit             
bn = bin(n) 
[int(bn[i:i+8], 2) for i in range(0,len(bn), 8)] 
    ....: 
100000 loops, best of 3: 3.96 µs per loop 

あなたはまた、単にdivmodことができます。

out = [] 
for _ in range(8): 
    n, i = divmod(n, 256) 
    out.append(i) 
out = out[::-1] 

これはほぼeと同じですfficient:

In [31]: %%timeit 
    ....: n = 2592701575664680411 
    ....: out = [] 
    ....: for _ in range(8): 
    ....:  n, i = divmod(n, 1 << 8) 
    ....:  out.append(i) 
    ....: out[::-1] 
    ....: 
100000 loops, best of 3: 2.35 µs per loop 

のpythonでビットシフトにはほとんど利点がありますが、私はあなたと他の人がより読みやすく見つけるものを使用する傾向になります。数値を文字列に変換することなく

8

ソリューション

対処:

x = 0b0010001111111011001000000101100010101010000101101011111000000000 

numbers = list((x >> i) & 0xFF for i in range(0,64,8)) 
print(numbers)     # [0, 190, 22, 170, 88, 32, 251, 35] 
print(list(reversed(numbers))) # [35, 251, 32, 88, 170, 22, 190, 0] 

説明

ここでIは8 i上の単位でループを作り、リストの内包を使用します。したがって、iの値は0, 8, 16, 24, 32, 40, 48, 56です。 ビットシフト演算子>>は、毎回xの数値をiビットだけ一時的にシフトします。これは、256^iで割ることと同じです。

だから、結果の数値は以下のとおりです。usig & 0xFFことで

i = 0: 0010001111111011001000000101100010101010000101101011111000000000 
i = 8:   00100011111110110010000001011000101010100001011010111110 
i = 16:     001000111111101100100000010110001010101000010110 
i = 24:       0010001111111011001000000101100010101010 
i = 32:         00100011111110110010000001011000 
i = 40:           001000111111101100100000 
i = 48:             0010001111111011 
i = 56:               00100011 

、私はこの番号の最後の8ビットを選択します。例:

x >> 48:   001000111111101100100000 
0xff:        11111111 
(x >> 48) & 0xff: 000000000000000000100000 

先頭のゼロは問題ではないため、必要な番号があります。

結果はリストに変換され、通常の順序と逆の順序で出力されます(OPが望むように)。

パフォーマンス

私はこのスレッドで提案されている他のソリューションには、この結果のタイミングを比較した:

In: timeit list(reversed([(x >> i) & 0xFF for i in range(0,64,8)])) 
100000 loops, best of 3: 13.9 µs per loop 

In: timeit [(x >> (i * 8)) & 0xFF for i in range(7, -1, -1)] 
100000 loops, best of 3: 11.1 µs per loop 

In: timeit [(x >> i) & 0xFF for i in range(63,-1,-8)] 
100000 loops, best of 3: 10.2 µs per loop 

In: timeit reversed(struct.unpack('8B', struct.pack('Q', x))) 
100000 loops, best of 3: 3.22 µs per loop 

In: timeit reversed(struct.pack('Q', x)) 
100000 loops, best of 3: 2.07 µs per loop 

の検索結果を:私の解決策は、最速ではありません! 現在、structを直接使用しています(Mark Ransomの提案通り)が最速のスニペットと思われます。ここで

+1

また、[(n >>(i * 8))&0xFFを範囲(7、-1、-1)] 'に入れて反転を忘れる –

+0

何らかの理由で、タイミングの結果が違ってきます。 Python 3.4.2で32ビットのiPython 2.0.0を使用しています。 64ビットWindowsマシン上。 – jojonas

+0

簡単な答えがあります。最初のコードでは何もしていません。リスト内にジェネレータ式があります。 –

2

structを使用したバージョンです:

import struct 
n = 2592701575664680400 
bytes = struct.unpack('8B', struct.pack('Q', n)) 

bytesは、あなたの質問に示した逆の順序で返されます。ここで

パフォーマンス統計情報は以下のとおりです。私のコンピュータで

python -m timeit -s "import struct" "struct.unpack('8B', struct.pack('Q', 2592701575664680400))" 
1000000 loops, best of 3: 0.33 usec per loop 

、これはバイトシフトソリューションよりも3倍高速です。

+1

おそらく、64ビット整数のバイトオーダー(例えば、ビッグエンディアン、 '>')を指定することによって、バイトが返される順序を制御することができます。 – Blckknght

関連する問題