2018/05/23

Python2系とPython3系では binascii.crc32 の計算結果が異なるので注意

python2 では signed、python3 では unsigned として扱われる

具体的な例としては以下。

python2
1
2
3
>>> import binascii
>>> binascii.crc32(b"Hello")
-137262718
python3
1
2
3
>>> import binascii
>>> binascii.crc32(b"Hello")
4157704578

数字は違うのですが、0xF7D18982 を 32bit の signed として扱っているか、unsigned として扱っているかの違いです。

そして、これは仕様のようです。

参考

Issue 4903: binascii.crc32() - document signed vs unsigned results - Python tracker

最上位ビットが 0 なら同じ

つまり、最上位ビットが 0 になる場合は python2 でも python3 でも計算結果は同じになります。

python2
1
2
3
>>> import binascii
>>> binascii.crc32(b"hello")
907060870
python3
1
2
3
>>> import binascii
>>> binascii.crc32(b"hello")
907060870

全部正の整数で取得したい場合

Python2 でも正の整数として取得したい場合は以下のようにします1

1
2
3
4
5
6
7
8
9
10
11
import binascii
 
 
def calc_crc32(bytes):
    """
    >>> calc_crc32(b"Hello")
    4157704578
    """
 
    crc32 = binascii.crc32(bytes)
    return crc32 & 0xFFFFFFFF

全部負の整数で取得したい場合

Python3 でも負の整数を出力したい場合は以下のようにします。

Python2 が混在する可能性がある場合、2系と3系で処理をわけないといけないので注意が必要です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import binascii
import sys
 
 
def calc_crc32(bytes):
    """
    >>> calc_crc32(b"Hello")
    -137262718
    """
 
    crc32 = binascii.crc32(bytes)
    if sys.version_info[0] == 3:
        return crc32 - ((crc32 & 0x80000000) << 1)
    return crc32
  1. 本筋とは関係ないですが、doctest で動作確認しました 
?

0 件のコメント: