Pythonでn進数の計算をする
Pythonで2進数、8進数および16進数と、10進数の相互間の変換をします。また、実際にはあまり使いませんが、7進数など中途半端な記進数との変換もご紹介します。
10進数から2,8,16進数に変換する
bin関数、oct関数、hex関数
2進数の表現方法
Pythonで2進数を表現する方法をご紹介します。
- #1 2進数の表現方法
- bi=0b1111
- bs='0b1111'
- print('値の比較:',bi,bs)
- print('typeの比較:',type(bi),type(bs))
- print('2倍:',bi*2,bs*2)
値の比較: 15 0b1111 typeの比較:2倍: 30 0b11110b1111
- 2進数を数字として扱うためには、頭2桁に2進数であることを示す0bを付け、そのあとに2進数の表現をします。10進数の15を2進数であらわすと1111(2)となりますが、2行目のようにbiという変数に’ ‘を付けずに0b1111を代入します。
- 2進数は英語でbinary numberといい、0bのように2進数を表す記号をbinary prefixといいます。prefixは接頭語を意味します。また、0b1111のような表現方法をBinary literalsといいます。
- 同じ2進数でも3行目のbsのように’ ‘を付けて表現する方法もあります。
- 4行目にあるように、それぞれの変数の形式を調べるとbiは整数、bsは文字列となります。
- このため、6行目のようにbiを2倍すると30となるので、biは整数15を表示だけ2進数に変換しているだけであることがわかります。一方’ ‘のついたbsは2倍すると文字列の連結になり、’0b1111’が2つ並ぶことになります。
10進数を2進数に変換するbin関数
10進数を2進数に変換するためのPythonの組み込み関数であるbin関数を使います。
- #2 10進数を2進数に変換する
- x2 = bin(15)
- print('15-->bin:',x2)
- print('bin-->type:',type(x2))
- y = bin(7)+bin(8)
- print('bin+bin:',y)
15-->bin: 0b1111 bin-->type:bin+bin: 0b1110b1000
- bin関数を使うと10進数の整数を2進数の文字列に変換することができます。10進数の15を渡すと2進数の’0b1111’が返ります。
- bin関数の結果を4行目のようにtype関数でみるとstr:文字列になります。
- このため、6行目にあるようにbin関数の結果を足し合わせると、文字列の連結になります。
8,16進数に変換するoct関数、hex関数
Pythonの組み込みモジュールには、8,16進数に変換することができるoct、hex関数が用意されています。
- #3 10進数を8進数、16進数に変換する
- x8 = oct(15)
- print('15-->oct:',x8)
- x16 = hex(255)
- print('255-->hex:',x16)
- print('hex-->bin:',bin(0xf))
- print('bin-->hex:',hex(0b1111))
15-->oct: 0o17 255-->hex: 0xff hex-->bin: 0b1111 bin-->hex: 0xf
- 2行目のように、10進数を8進数に変換するためにはoct関数を使います。結果の頭2桁には0o(ゼロ、オー、octal prefix)が付きます。
- 4行目のように、10進数を16進数に変換するためにはhex関数を使います。結果の頭2桁には0x(hexadecimal prefix)が付きます。
- 6行目では、16進数の数字をbin関数で2進数に変換しています。10進数の15は、16進数ではoxfとなりますが、hexadecimal prefixがついているので16進数であることがわかり、これを2進数に変換しています。
- 7行目では、2進数の数字をhex関数で16進数に変換しています。10進数の15は2進数では0b1111となりますが、binary prefixがついているので2進数であることがわかり、これを16進数に変換しています。
このようにbin、hex関数は10進数からでなくても、指定する記進数に変換することができます。2進数、8進数、16進数はコンピュータを扱う上で必須のものであるからですが、pythonの組み込み関数には、これ以外のn進数に変換するものは見つかりません。
NumPyモジュールによるn進数への変換
NumPyモジュールのbase_repl関数を使うと10進数を2,8,16進数だけでなく、任意のn進数に変換することができます。
base_repr関数考え方
- #4 NumPyで10進数をn進数に変換する
- import numpy as np
- print('int-->bin:',np.base_repr(15, base=2))
- print('int-->oct:',np.base_repr(15, base=8))
- print('int-->hex:',np.base_repr(255, base=16)) # 255=16**2-1
- print('int-->5進数:',np.base_repr(6, base=5))
- print('int-->36進数 :',np.base_repr(1679615, base=36)) # 1679615=36**4-1
int-->bin: 1111 int-->oct: 17 int-->hex: FF int-->5進数: 11 int-->36進数 : ZZZZ
- base_repl関数は、1つ目の引数に変換したい数字、2つ目の引数に変換したい基数を指定します。3行目では10進数の15を2進数に変換しています。
- 4,5行目では8、16進数に変換しています。16進数では、アルファベットの表示は大文字になります。
- 6行目では、10進数6を5進数の11(5)に変換しています。このように、2,8,16進数以外の記進法にも変換することができます。
- 変換できるのは、7行目のように36進数が上限で、37以上の記数を指定するとエラーになります。10を超える部分はABC・・・Zと大文字アルファベット(26文字)を使って表現するので、その合計が36となるためです。
base_repr関数の応用
NumPyモジュールのbase_repr関数の活用方法について補足します。
- #5 np.base_repr関数の応用
- import numpy as np
- print('int-->hex padding 4桁:',np.base_repr(0xf, base=2))
- print('int-->hex padding 4桁:',np.base_repr(255, base=16, padding=4))
- print('int-->hex padding 2桁:',np.base_repr(255, 2, 2))
- print('int-->n進数default:',np.base_repr(15))
hex-->bin: 1111 int-->hex padding 4桁: 0000FF int-->hex padding 2桁: 0011111111 int-->n進数default: 1111
- 3行目のように、base_repr関数は1つ目の引数で10進数以外の数字を渡しても他の記進法に変換することができます。
- 4行目のようにpaddingを指定すると、本来表示する桁数にpaddingで指定した桁数分の0 を補って表示します。
- 2の方法は5行目にようにbase、paddingを明示しなくても同じ効果になります。
- 逆に6行目のように2つめの引数を指定しないと、defaultで2進数に変換されます。
10進数から2,8,16進数に変換する
bin,oct,hex関数の逆のint関数
2進数を返すbin関数は0b、 8進数を返すoct関数は0o、 16進数を返す hex関数は0xというように、prefix付きの文字列で返します。この逆で、’ ‘無しの数値としての記進数としての表現にint関数を適用すると、対応する10進数を返します。
- #6 int関数で2,8,16進数を10進数に変換
- print('bin-->int:',int(0b1111))
- print('oct-->int:',int(0o17))
- print('hex-->int:',int(0xff))
- print('int',type(int(0xff)))
bin-->int: 15 oct-->int: 15 hex-->int: 255 int
int関数なので、5行目にあるように整数として返されます。
任意のn進数を10進数の数値に変換するint関数
int関数では、0b1111の0bのような prefixがついていない、つまり記数かわからない文字列でも10進数に変換することができます。この方法によると、2,8,16進数以外の記数のものからも10進数に変換することができます。
- #7 int関数で任意のn進数を10進数の数字に変換
- print('bin-->int:',int('1111',base=2))
- print('oct-->int:',int('17',8))
- print('hex-->int:',int('ff',16))
- print('hex-->int:',int('1111'))
- print('5進数-->int:',int('11',5))
- print('36進数-->int:',int('ZZZZ',36))
- print('36進数-->int:',int('aBcD',30))
- print('文字列としてのbinaryを変換:',eval('0xff'))
bin-->int: 15 oct-->int: 15 hex-->int: 255 hex-->int: 1111 5進数-->int: 6 5進数-->int: 6 36進数-->int: 1679615 36進数-->int: 280273 文字列としてのbinaryを変換: 255
- 2行目では1つ目の引数’1111”に対し、2つ目の引数で2進数を設定して変換しています。1つ目の引数は文字列(’ ’付き)で指定します。
- 5行目では記数を省略しています。この場合、base_repr関数とは異なり、単純に文字列を整数に変換する(10進数に変換される)だけになります。
- 6行目では、’ ‘付きの数字を示す文字列を5進数に変換できることがわかります。
- 7行目のように指定できる最大の記数は36で、37以上の数字を指定するとエラーになります。8行目にあるように、英字の場合は大文字、小文字が混在しても大丈夫です。
- int関数は、’ 0xff’の’0x’ようなprefix付きの文字列を10進数に変換しようとするとエラーになります。この場合、9行目のようにeval関数を使うと正しく変換されます。
2,8,16進数を10 進数の文字列に変換するstr関数
str関数は、prefix付きの記進数の’ ‘無しの数値表現に対し、10進数を示す文字列に変換します。
- #8 str関数で2,8,16進数を10進数の文字列に変換
- print('bin-->str:',str(0b1111))
- print('bin-->str:',type(str(0b1111)))
- print('oct-->str:',str(0o17))
- print('hex-->str:',str(0xff))
bin-->str: 15 bin-->str:oct-->str: 15 hex-->str: 255
実際には、使う場面はあまり想定されません。
format関数、formatメソッドで書式変換する
pythonの組み込み関数のなかでformat関数、formatメソッドには多彩な機能があります。この中で記進数に関するものをまとめます。
format関数により10進数をn進数に変換
format関数を使うと、10進数を含めて記進表の表現記相互間で書式を変換することができます。
format関数で10進数をprefix無しのn進数に変換する
format関数の引数は変換元の数字と、変換後の進数を指定します。
- #9 format関数を使ったn進数の書式変換
- print('int-->bin:',format(15,'b'))
- print('formatの書式:',type(format(15,'b')))
- print('int-->oct:',format(15,'o'))
- print('int-->hex:',format(255,'x'))
- print('int-->HEX:',format(255,'X'))
int-->bin: 1111 format関数の書式:int-->oct: 17 int-->hex: ff int-->HEX: FF
- 2行目のように、1番目の引数に10進数、2番目の引数に2進数を示す”b”を渡すと、”1111”のような文字列に変換されます。
- 3行目にあるように、変換された書式はprefix無しの文字列になります。
- 4~6行目にように、8進数は”o”、16進数は英字の桁を小文字にするときは”x”、大文字にするときには”X”を設定します。
format関数で10進数をn進数にprefix付きで変換する
#9と同じformat関数で表記を変換していますが、format関数の2つめの引数で’#b’のように”#”を付けると、出力にはprefixが付きます。
- #10 format関数を使ったn進数へのprefix付きの書式変換
- print('int-->bin:',format(15,'#b'))
- print('int-->oct:',format(15,'#o'))
- print('int-->hex:',format(255,'#x'))
- print('int-->HEX:',format(255,'#X'))
int-->bin: 0b1111 int-->oct: 0o17 int-->hex: 0xff int-->HEX: 0XFF
format関数を使ったn進数prefix付きの桁数指定の書式変換
#10に加え、記進数を示す’b”のような記進数をあらわす文字の前に桁数を数字で指定すると、指定した数値の桁数になるまで0を補って表示します。
- #11 format関数を使ったn進数prefix付きの桁数指定の書式変換
- print('int-->#無し+0無し数字:',format(15,'8b'))
- print('int-->#無し+0有り数字:',format(15,'08b'))
- print('int-->bin:',format(15,'#08b'))
- print('int-->oct:',format(15,'#08o'))
- print('int-->hex:',format(255,'#06x'))
- print('int-->HEX:',format(255,'#06X'))
- print('int-->bin 8桁以上:',format(1000,'#08b'))
int-->#無し+0無し数字: 1111 int-->#無し+0有り数字: 00001111 int-->bin: 0b001111 int-->oct: 0o000017 int-->hex: 0x00ff int-->HEX: 0X00FF int-->bin 8桁以上: 0b1111101000
- 2行目でformat関数の2つ目の引数で、’8b’のように’#’無しで数値を指定しています。15を2進数で表示すると1111と4桁で済むので、残り4桁にブランクを補います。全体が8桁になるように表示するわけです。
- 3行目のように’08b’のように2つ目の引数の頭1桁に’0’を付けると、ブランクでなく0を補います。0の有無については以下も同じです。
- 4行目のように、’#08b’と指定すると、ob1111とprefixも含めて6桁で表示できますが、08と指定しているので、0を2桁補って全体として8桁になるように表示します。
- 5~7行目も同様に8進数、16進数も同じ結果になります。
- 7行目のように、数値を8桁と指定しても結果が8桁を超えるときは、当然その桁数で表示されます。つまり、ここで指定する桁数の数値は出力の最小の桁数であることを示します。
format関数でn進数を10進数に変換する
format関数により、prefix付きの書式を10進数に変換する
前節とは逆に、format関数で10進数に変換することができます。
- #12 format関数を使ったprefix付きの書式を10進数に変換
- print('bin-->dec:',format(0b1111,'d'))
- print('oct-->dec:',format(0o17,'d'))
- print('hex-->dec:',format(0xff,'d'))
- print('bin-->6桁dec:',format(0xff,'06d'))
bin-->dec: 15 oct-->dec: 15 hex-->dec: 255 bin-->6桁dec: 000255
- 2行目にあるようにformat関数で1つ目の引数にprefix付きで’ ‘の無いn進数の数字を、2つ目の引数に’d’を渡すと、10進数の数字に変換することができます。
- この場合、3行目にあるように書式は数字でなく文字列になります。
- 5行目のように、dの前に数字を指定するとその桁数に足りない部分は0を補って表示されます。
format関数を使ったprefix付きの書式を間の変換する
format関数でも、10進以外の記進数間の変換も可能です。
- #13 format関数を使ったprefix付きの書式を間の変換
- print('bin-->hex:',format(0b1111,'#x'))
- print('hex-->bin:',format(0xf,'#b'))
bin-->hex: 0xf hex-->bin: 0b1111
上記のように、10進数を介さなくても、2進数、8進数、16進数相互間で変換することができます。
formatメソッドによる書式変換
pythonでは、数字などを見やすい書式に変換するときにはformatメソッドを使うと、とても便利です。
formatメソッドで数字を書式変換する
- #14 formatメソッドによる書式変換
- print("{:b}".format(15))
- print(type("{:b}".format(15)))
- print("{:o}".format(15))
- print("{:x}".format(255))
- print("{:X}".format(255))
111117 ff FF
- 2行目にあるように、{:b}というように、2進数であるとの書式を設定し、formatで10進数の数字を指定すると、
- 1の結果は文字列になります。
- 4行目、5行目のように、数字を8進数、16進数の文字列に変換することができます。10進数以上で英字が現れる場合、書式を指定する{:X}のように大文字を指定すると、これに対応して英字も大文字で表示されます。
formatメソッドを使った表現
formatメソッドを使うと、文章の中に記進法の表現を埋め込むことができます。
- #15 formatメソッドによる複雑な表現
- print("10進数で{:d} は、2進数で {:b} です".format(15, 15))
- print("10進数で{0:d} は、2進数で {1:b} です".format(15, 15))
- print("10進数で{0:d} は、2進数で {0:b} です".format(15))
10進数で15 は、2進数で 0b1111 です 10進数で15 は、2進数で 0b1111 です 10進数で15 は、2進数で 0b1111 です
- 2行目では、中括弧囲いが{:d}と{:#b}の2つあり、formatの2つ引数の引数(15,15)にそれぞれ対応しています。1つめの15は{0:d}、つまり0番目の項目として10進数で表示します。2つめの15は1番目の項目として{1:#b}、つまりprefix付きの2進数で表示します。
- 3行目のように、順番を示す0,1 という引数は省略することもできます。この場合には、中括弧とformatの中の引数の順番が対応します。
- 1,2では同じ15という数字を書式変換するのに、formatの中で15を2回記述する必要があります。この場合、4行目のように{0:d}{0:#b}というようにともに0番目の順序を指定するとこのような無駄を省くことができます。
formatメソッドの応用
#15の方法を応用すると、1からnで指定した数までの、2進数、8進数、16進数の一覧を出力することができます。
- #16 formatメソッドの応用
- n=100
- width = len("{0:b}".format(n))+1
- print ("| {:^{width}} | {:^{width}} | {:^{width}} | {:^{width}}| ".format('Dec','Oct','Hex','Bin',width=width))
- print ("+ {0:^{width}} + {0:^{width}} + {0:^{width}} + {0:^{width}}+ ".format('-'*(width),width=width))
- for i in range(1,n+1):
- print ("| {0:{width}d} | {0:{width}o} | {0:{width}x} |{0:{width}b} |".format(i, width=width))
特徴として最も桁数が多くなるnを2進数にしたときの桁数に合わせて列幅にできることです。3行目で列幅を変数wで計算し、{}の中でwidthを指定しますが、ここにformatメソッドでwidthに代入します。