2018/05/23

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

### python2 では signed、python3 では unsigned として扱われる
具体的な例としては以下。

```python
`title: "python2";
>>> import binascii
>>> binascii.crc32(b"Hello")
-137262718
```

```python
`title: "python3";
>>> import binascii
>>> binascii.crc32(b"Hello")
4157704578
```

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

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

> 参考
>
> [Issue 4903: binascii.crc32() - document signed vs unsigned results - Python tracker](https://bugs.python.org/issue4903)



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

```python
`title: "python2";
>>> import binascii
>>> binascii.crc32(b"hello")
907060870
```

```python
`title: "python3";
>>> import binascii
>>> binascii.crc32(b"hello")
907060870
```

### 全部正の整数で取得したい場合
Python2 でも正の整数として取得したい場合は以下のようにします本筋とは関係ないですが、doctest で動作確認しました。

```python
import binascii


def calc_crc32(bytes):
    """
    >>> calc_crc32(b"Hello")
    4157704578
    """

    crc32 = binascii.crc32(bytes)
    return crc32 & 0xFFFFFFFF
```


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

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

```python
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
```

0 件のコメント: