質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

4891閲覧

pythonでの符号付き8ビット変換について

takeshi_yama

総合スコア4

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2021/10/27 01:46

前提・実現したいこと

pythonでの符号付き8ビットの変換をしたい

該当のソースコード

python

1a = 0b11110011 2print(a)#243と表示されるのを-13と表示したい 3 4x = 0b01110011 5print(-0b10000000|x)#これが正解のよう 6print(0b10000000|-x) 7print(-(0b10000000|x))

試したこと

前提・実現したいこと

pythonでの符号付き8ビットの変換をしたい
該当のソースコード

a = 0b11110011
から下位7ビット分を抜き出したものをxとする。
x = 0b1110011

-0b10000000|x
を実行すると、負の値が表示されました。

ただ、どうしてこのようになるのかが良くわかりません。
なぜ
・print(-0b10000000|x) #-13
・print(0b10000000|-x) #-115

とで出てくる値が異なるのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

前提

pythonの整数型と数値リテラルの話

pythonの数値型はint, float, complexの3種類です。
https://docs.python.org/ja/3/library/stdtypes.html#numeric-types-int-float-complex

これに定数値を代入するのに数値リテラルが使用されます。
https://docs.python.org/ja/3.10/reference/lexical_analysis.html#numeric-literals

整数を表す数値リテラルは10進数整数値、2進数整数値、8進数整数値、16進数整数値から選べますが、何を使ったとしても型としてはintになります

例えば、

  • 10進数整数値の256
  • 2進数整数値の0b100000000
  • 8進数整数値の0o400
  • 16進数整数値の0x100

は全て同じint型の値になります。

符号はリテラルの一部ではないのですが、符号もつけると

  • 10進数整数値の-256
  • 2進数整数値の-0b100000000
  • 8進数整数値の-0o400
  • 16進数整数値の-0x100

も同じく、全て同じint型の値になります。

pythonのint型の桁数の話

そしてpythonの整数型intは桁数に制限がありません

なので、「符号付き8ビットの変換」という表現は適切ではなく、2の補数表現
https://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0
で8桁の数値にするならどうするか?と考えるべきです。

負数を2の補数で表現する話

任意の整数xbitsビットの2の補数で表現される正数に変換するコードは↓な感じになります。

python

1>>> def convert_to_nbits_from_int(x, bits): 2... if x > (1<<(bits-1))-1 or x < -(1<<(bits-1)): 3... raise(ValueError(x)) 4... if x < 0: 5... x += 1 << bits 6... return x 7... 8>>> x=convert_to_nbits_from_int(0, 8); x, bin(x) 9(0, '0b0') 10>>> x=convert_to_nbits_from_int(1, 8); x, bin(x) 11(1, '0b1') 12>>> x=convert_to_nbits_from_int(127, 8); x, bin(x) 13(127, '0b1111111') 14>>> x=convert_to_nbits_from_int(128, 8); x, bin(x) 15Traceback (most recent call last): 16 File "<stdin>", line 1, in <module> 17 File "<stdin>", line 3, in convert_to_nbits_from_int 18ValueError: 128 19>>> x=convert_to_nbits_from_int(-128, 8); x, bin(x) 20(128, '0b10000000') 21>>> x=convert_to_nbits_from_int(-129, 8); x, bin(x) 22Traceback (most recent call last): 23 File "<stdin>", line 1, in <module> 24 File "<stdin>", line 3, in convert_to_nbits_from_int 25ValueError: -129 26>>> x=convert_to_nbits_from_int(-1, 8); x, bin(x) 27(255, '0b11111111') 28>>>

ただし、元々Pythonのビット演算は負値を2の補数で扱うため、
https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types

例外をあげないことにすれば単純に

python

1>>> def convert_to_nbits_from_int(x, bits): 2... return x & ((1 << bits) - 1) 3... 4>>>

と書くことができます。

逆にbitsビットの2の補数で表現された任意の値xを元の数値に戻すには、(質問にあるとおり)

python

1>>> def convert_to_int_from_nbits(x, bits): 2... return (-(x & (1<<(bits-1)))) | (x & ((1<<(bits-1))-1)) 3... 4>>> convert_to_int_from_nbits(255, 8) 5-1 6>>> convert_to_int_from_nbits(128, 8) 7-128 8>>> convert_to_int_from_nbits(127, 8) 9127 10>>> convert_to_int_from_nbits(1, 8) 111 12>>> convert_to_int_from_nbits(0, 8) 130 14>>>

のような形に書けます。

回答

上記の説明から、質問文のa243という正の整数値であり、x115という正の整数値です。
ただ最後にご質問されている数値には負数が混ざっており、そのビット演算は2の補数表現で行われるため、一度2の補数表現を使用した整数値に変換して全て正数演算するコードを以下に記述しました。

質問文の-0b10000000|x

python

1>>> convert_to_int_from_nbits(convert_to_nbits_from_int(-0b10000000,9) | convert_to_nbits_from_int(x,9), 9) 2-13

となります。

質問文の0b10000000|-x

python

1>>> convert_to_int_from_nbits(convert_to_nbits_from_int(0b10000000, 9) | convert_to_nbits_from_int(-x,9), 9) 2-115

となります。

質問文の-(0b10000000|x)

python

1>>> -convert_to_int_from_nbits(convert_to_nbits_from_int(0b10000000, 9) | convert_to_nbits_from_int(x,9), 9) 2-243

となります。

※9桁にしているのは、0b10000000=128など8桁の2の補数では表現できない数字が出現するからです

投稿2021/10/28 12:34

編集2021/10/28 12:38
dameo

総合スコア943

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takeshi_yama

2021/11/04 06:20

とても詳しい解説をありがとうございます。 皆様の回答を一つ一つ読み解いていき、やっと頭の整理ができた気がします。
guest

0

  • pythonでの符号付き8ビットの変換をしたい

一番簡単なのはnumpyの符号付き8ビット整数を使うことです。

python

1>>> import numpy as np 2>>> print(np.int8(0b11110011)) 3-13

投稿2021/10/27 02:10

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

場合分けするか、パック・アンパックするか。

Python

1x = 0b~~~ 2 3y = x if x<0b10000000 else -0b10000000|x 4print(y) 5 6import struct 7z = struct.unpack("b",struct.pack("B",x))[0] 8print(z)

投稿2021/10/27 02:08

otn

総合スコア84555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2021/10/27 02:11

パック→数値等をバイト表現に アンパック→バイト表現を数値等に
guest

0

python には、8ビットの型というのがないはずですから

8ビットの最上位ビットを 符号ビットとして特別扱いします。

python

1a = 0b11110011 2 3b = -(a & 0b10000000) | (a & 0b01111111) 4 5print(b)

で、-13 が出力されます。
一般化するには 関数化しちゃうのがいいかと思います。
詳細は
Pythonで符号付き8bit整数を扱う(2の補数)
をご参照ください(わたしも ここを読みました 笑)。

投稿2021/10/27 01:57

showkit

総合スコア1638

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問