全くの別件で検索していてでてきた18 I2c通信で気圧,標高を取得しよう.(LPS331AP気圧センサ)(http://lumenbolk.com/?p=814)というページではたぶんセンサからI2Cでデータを取り出すところが中心と思います。が、公開されているPythonスクリプト中の2の補数計算(符号付き整数16進→10進変換)をベタ書きしているのを見て妙に気になりました(ページの本筋からは外れます)。補数計算をPython3で関数化するとどうなるか?気になったので作ってみました。私が実際に必要になったときにはまず忘れているのでここにメモしておきます。標準関数でありそうなのに無いらしい。
符号をMSBから取り出すためにビット位置指定する方法はpythonのビット操作について(http://python-remrin.hatenadiary.jp/entry/2017/05/31/162927)を参考にしました。Pythonのビット演算は少し特殊?かと思いました。確認しながら組み立てていけば問題は無いと思いますが一度に長い処理を書くには慣れが必要かと思いました。
スクリプトは以下の通りです。全パターンチェックしているわけではありません。たぶん、64bitぐらいまでは大丈夫ではないか?と思います。
""" 2の補数計算 """ # -*- coding:utf-8 -*- #http://lumenbolk.com/?p=814 #http://python-remrin.hatenadiary.jp/entry/2017/05/31/162927 def calc_2s_complement(bitsuu, nyuuryoku): if nyuuryoku & pow(2, (bitsuu-1)): # MSB == 1 (負の数) nyuuryoku = -((nyuuryoku ^ (pow(2, bitsuu)-1))+1) return nyuuryoku if __name__ == '__main__': print(calc_2s_complement(8, 0x00)) print(calc_2s_complement(8, 0x01)) print(calc_2s_complement(8, 0x7f)) print(calc_2s_complement(8, 0x80)) print(calc_2s_complement(8, 0xff)) print(calc_2s_complement(16, 0x0000)) print(calc_2s_complement(16, 0x0001)) print(calc_2s_complement(16, 0x7fff)) print(calc_2s_complement(16, 0x8000)) print(calc_2s_complement(16, 0xffff)) print(calc_2s_complement(24, 0x00_0000)) print(calc_2s_complement(24, 0x00_0001)) print(calc_2s_complement(24, 0x7f_ffff)) print(calc_2s_complement(24, 0x80_0000)) print(calc_2s_complement(24, 0xff_ffff)) print(calc_2s_complement(32, 0x0000_0000)) print(calc_2s_complement(32, 0x0000_0001)) print(calc_2s_complement(32, 0x7fff_ffff)) print(calc_2s_complement(32, 0x8000_0000)) print(calc_2s_complement(32, 0xffff_ffff))
おまけめも)さらに脱線するとPythonでは数値や文字列がimmutableという点にも違和感があったりします。なかなか慣れません。