らずぱいでIoT 第8回(16Bit幅の補数計算検証)
らずぱいでIoT 第8回(16Bit幅の補数計算検証)
pythonのint型変数の扱いには少し注意が必要です。 python3のint型は最大のBit幅に制限なくShortやLongといった区別がなくなりました。 そのため前回の16Bit長のレジスタ値のマイナス表現でpythonが認識しているbit幅に拡張する場合どう描くべきかをC言語のプログラムを使い見てみます。 その前に補数について少し触れておくと 計算機内部では、マイナス値がどのように扱われているかという事を見てみると 1Byte=8bit長の2進数で表現可能で計算機内部では5という数字は 00000101 という2進数です。 この5をある数字から引きたい場合、計算機の中でどのようなことが起きるかというとビットを反転させる解くことが起きていますなので5は 11111010 という2進数になりこれを1の補数といいます。 1の補数表現の5にある数字を足すと例えば十進法の10を足すと十進法の10は2進法で 00001010 なので 11111010+00001010 = 100000100 となりますが8bit幅なので最上位の1が無くなり 00000100 = 十進法の4 となります。 上の2進数の式を10進法で見てみると 250 + 10 = 260 で8bitで表される最大数は255なのであふれた分を計算すると5という10-5の答えが得られます。 では1の補数で計算するとなぜ答えが4になるかというと計算機内部で最上位ビットを符号とした場合 2進数の10000000は-0というおかしな値が存在しているためで、この分符号反転した時点で1を足さないとつじつまが合わないということが起きます。このようにビット反転して1を足した補数を2の補数と呼びます。 2の補数で計算してみると 11111011+00001010 = 100000101 となり2進数でも正しい値が出てきます。 これを踏まえた上で、16Bit幅のマイナス値をpythonのint型に拡張する場合どうするかをpythonではBit幅が確定されていないのでC言語で試してみたいと思います。 ーーーーーーーーーーーーーーーーーーーーーーーーーーーー 以下プログラム #include <stdio.h> void main() { unsigned short n = 0xfff5; _______ short m; ____ printf("単純にマイナス %04x->%d(%08x)\n",n,-n,-n); ____ // 16Bit幅で2の補数表現に変換 ____ m=(-n ^ 0xffff)+1; ____ printf("2の補数表現に変換 %08x -> %d\n",m,m); ____ printf("-11のビット確認 %08x -> %d\n",(short)-11,(short)-11); } ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーここまで なお_はスペースを示します。 最初のpirntfではunsigned short(32bit)の変数に0xfff5(16bit)をいれて単純にマイナスに変換すると32Bit幅で2の補数値が計算され0xffff000bとなります。 そのため下位16ビット幅で2の補数を計算してみると 0xfffffff5という値に拡張されていることがわかります。(2番目のprintf) 念のため32Bit長の-11が32bitはばで0xfffffff5であることを確認してみます。(3番目のprintf) ということでpythonで拡張できるかを以下のプログラムで確認してみると ーーーーーーーーーーーーーーーーーーーーーーーーーーーー ここから python #!/usr/bin/python n=0xfff5 print("%x -> %d\n" % (n,(-n ^ 0xffff)+1)) ーーーーーーーーーーーーーーーーーーーーーーーーーーーー ここまで ということで16Bitのマイナス値をPythonの持つ不確定長の整数型に上記の式で拡張できることが検証できます。 今回使用したCのソースとPythonのソースはここからダウンロードできます。