開発環境
- macOS Mojave - Apple (OS)
- Emacs (Text Editor)
- Windows 10 Pro (OS)
- Visual Studio Code (Text Editor)
- Python 3.7 (プログラミング言語)
プログラマの数学第2版 (結城 浩 (著)、SBクリエイティブ)の第1章(ゼロの物語 - 「ない」ものが「ある」ことの意味)、2進法が出てくるのは、コンピュータで2進法が使われている理由で詳しい記述があったけど、位取り記数法の位取り記数法とは何かに、
プログラミングでは、8進法や16進法もよく使われます。とあるものの、何故8進法や16進法がよく使われるかの記述が見当たらなかったので、16進数について何故使われるかを視覚的に表してみた。
8進数については、ファイルのパーミッション等の変更の時に使われるのをみたことはあるけど、実際に自身では使ったことがほとんどないので使用例のみ。ファイルのパーミッション等の変更の時は8進数による絶対モード指定ではなく、文字列によるモードの指定を使うから。
コード
Python 3
#!/usr/bin/env python3 print('Hello, world!')
入出力結果(cmd(コマンドプロンプト)、Terminal、Jupyter(IPython))
$ ls -l sample.py -rw-r--r-- 1 kamimura staff 47 2 1 11:55 sample.py $ ./sample.py bash: ./sample.py: Permission denied $ chmod 0755 sample.py $ ls -l sample.py -rwxr-xr-x 1 kamimura staff 47 2 1 11:55 sample.py* $ ./sample.py Hello, world! $ chmod 0644 sample.py $ ls -l sample.py -rw-r--r-- 1 kamimura staff 47 2 1 11:55 sample.py $ ./sample.py bash: ./sample.py: Permission denied $ chmod a+x sample.py $ ls -l sample.py -rwxr-xr-x 1 kamimura staff 47 2 1 11:55 sample.py* $ ./sample.py Hello, world! $ chmod a-x sample.py $ ls -l sample.py -rw-r--r-- 1 kamimura staff 47 2 1 11:55 sample.py $ ./sample.py bash: ./sample.py: Permission denied $
上記のコードでしていることは、sample.pyファイルに全てのユーザーが実行可能な権限を与えたり、その権限を削除したり。
文字列によるモードの指定は全てのユーザー(allの頭文字)に実行権限(executeのx)を与える(+)、削除する(-)ということで、「a+x」、「a-x」と指定。
4桁の8進数の先頭の0についての説明は省略。残り3桁について、左から全てのユーザー、グループのユーザー、その他のユーザーと割り当てる。ここで、各ユーザーの権限について、読み込み可能(r)、書き込み可能(w)、実行可能(x)の3種類ある。ここで3桁の2進数を考える。左から順に、各権限について可能ならば1、不可能ならば0とすれば、各ユーザーが読み込み、書き込み、実行可能な場合は111、読み書きのみ可能なのは110、読み込みと実行可能がな場合は101、読み込みのみ可能な場合は100となる、これを8進数に変換すると、それぞれ7、6、5、4となる。よって、「a+x」と等価なのは、0755、「a-x」と等価なのは0644となる。
8進数による指定より、文字列による指定の方が分かりやすいから、これが8進法をほとんど使うことがない理由。(プログラミングの他の分野等で8進数がよく使われる分野がもしかしたらあるのかも。)
8進数と違って16進数をよく使う理由を視覚化。前回定義した関数を利用。
コード
Python 3
#!/usr/bin/env python3 def to_bin(n: int) -> str: ''' >>> to_bin(12) '1100' ''' ''' 10進数を2進数に変換 ''' b = '' while n != 0: n, r = divmod(n, 2) b = f'{r}{b}' if b == '': return '0' return b def from_bin(bin: str) -> int: ''' >>> from_bin('1100') 12 ''' ''' 2進数を10進数に変換 ''' n = 0 for c in bin: n *= 2 n += int(c) return n # 一般化 def to_n(num: int, n: int) -> str: ''' >>> to_n(12, 2) '1100' >>> to_n(12, 8) '14' >>> to_n(12, 16) 'c' ''' ''' 10進数をn進数に変換 ''' m = '' while num != 0: num, r = divmod(num, n) if r >= 10: r -= 10 m = f'{chr(ord("a") + r)}{m}' else: m = f'{r}{m}' if m == '': return '0' return m def from_n(s: str, n: int) -> int: ''' >>> from_n('1100', 2) 12 >>> from_n('14', 8) 12 >>> from_n('c', 16) 12 ''' ''' n進数を10進数に変換 ''' m = 0 for c in s: m *= n if c >= 'a': m += 10 + ord(c) - ord('a') else: m += int(c) return m def n_to_m(s: str, n: int, m: int) -> str: ''' >>> n_to_m('1100', 2, 8) '14' >>> n_to_m('1100', 2, 16) 'c' >>> n_to_m('14', 8, 2) '1100' >>> n_to_m('c', 16, 2) '1100' ''' ''' n進数をm進数に変換 ''' return to_n(from_n(s, n), m) if __name__ == '__main__': import doctest doctest.testmod() for n in range(2 ** 8): b = to_bin(n) h = n_to_m(b, 2, 16) print(f'{n:3} {b:0>8} {h:0>2}')
入出力結果(cmd(コマンドプロンプト)、Terminal、Jupyter(IPython))
$ python3 sample.py 0 00000000 00 1 00000001 01 2 00000010 02 3 00000011 03 4 00000100 04 5 00000101 05 6 00000110 06 7 00000111 07 8 00001000 08 9 00001001 09 10 00001010 0a 11 00001011 0b 12 00001100 0c 13 00001101 0d 14 00001110 0e 15 00001111 0f 16 00010000 10 17 00010001 11 18 00010010 12 19 00010011 13 20 00010100 14 21 00010101 15 22 00010110 16 23 00010111 17 24 00011000 18 25 00011001 19 26 00011010 1a 27 00011011 1b 28 00011100 1c 29 00011101 1d 30 00011110 1e 31 00011111 1f 32 00100000 20 33 00100001 21 34 00100010 22 35 00100011 23 36 00100100 24 37 00100101 25 38 00100110 26 39 00100111 27 40 00101000 28 41 00101001 29 42 00101010 2a 43 00101011 2b 44 00101100 2c 45 00101101 2d 46 00101110 2e 47 00101111 2f 48 00110000 30 49 00110001 31 50 00110010 32 51 00110011 33 52 00110100 34 53 00110101 35 54 00110110 36 55 00110111 37 56 00111000 38 57 00111001 39 58 00111010 3a 59 00111011 3b 60 00111100 3c 61 00111101 3d 62 00111110 3e 63 00111111 3f 64 01000000 40 65 01000001 41 66 01000010 42 67 01000011 43 68 01000100 44 69 01000101 45 70 01000110 46 71 01000111 47 72 01001000 48 73 01001001 49 74 01001010 4a 75 01001011 4b 76 01001100 4c 77 01001101 4d 78 01001110 4e 79 01001111 4f 80 01010000 50 81 01010001 51 82 01010010 52 83 01010011 53 84 01010100 54 85 01010101 55 86 01010110 56 87 01010111 57 88 01011000 58 89 01011001 59 90 01011010 5a 91 01011011 5b 92 01011100 5c 93 01011101 5d 94 01011110 5e 95 01011111 5f 96 01100000 60 97 01100001 61 98 01100010 62 99 01100011 63 100 01100100 64 101 01100101 65 102 01100110 66 103 01100111 67 104 01101000 68 105 01101001 69 106 01101010 6a 107 01101011 6b 108 01101100 6c 109 01101101 6d 110 01101110 6e 111 01101111 6f 112 01110000 70 113 01110001 71 114 01110010 72 115 01110011 73 116 01110100 74 117 01110101 75 118 01110110 76 119 01110111 77 120 01111000 78 121 01111001 79 122 01111010 7a 123 01111011 7b 124 01111100 7c 125 01111101 7d 126 01111110 7e 127 01111111 7f 128 10000000 80 129 10000001 81 130 10000010 82 131 10000011 83 132 10000100 84 133 10000101 85 134 10000110 86 135 10000111 87 136 10001000 88 137 10001001 89 138 10001010 8a 139 10001011 8b 140 10001100 8c 141 10001101 8d 142 10001110 8e 143 10001111 8f 144 10010000 90 145 10010001 91 146 10010010 92 147 10010011 93 148 10010100 94 149 10010101 95 150 10010110 96 151 10010111 97 152 10011000 98 153 10011001 99 154 10011010 9a 155 10011011 9b 156 10011100 9c 157 10011101 9d 158 10011110 9e 159 10011111 9f 160 10100000 a0 161 10100001 a1 162 10100010 a2 163 10100011 a3 164 10100100 a4 165 10100101 a5 166 10100110 a6 167 10100111 a7 168 10101000 a8 169 10101001 a9 170 10101010 aa 171 10101011 ab 172 10101100 ac 173 10101101 ad 174 10101110 ae 175 10101111 af 176 10110000 b0 177 10110001 b1 178 10110010 b2 179 10110011 b3 180 10110100 b4 181 10110101 b5 182 10110110 b6 183 10110111 b7 184 10111000 b8 185 10111001 b9 186 10111010 ba 187 10111011 bb 188 10111100 bc 189 10111101 bd 190 10111110 be 191 10111111 bf 192 11000000 c0 193 11000001 c1 194 11000010 c2 195 11000011 c3 196 11000100 c4 197 11000101 c5 198 11000110 c6 199 11000111 c7 200 11001000 c8 201 11001001 c9 202 11001010 ca 203 11001011 cb 204 11001100 cc 205 11001101 cd 206 11001110 ce 207 11001111 cf 208 11010000 d0 209 11010001 d1 210 11010010 d2 211 11010011 d3 212 11010100 d4 213 11010101 d5 214 11010110 d6 215 11010111 d7 216 11011000 d8 217 11011001 d9 218 11011010 da 219 11011011 db 220 11011100 dc 221 11011101 dd 222 11011110 de 223 11011111 df 224 11100000 e0 225 11100001 e1 226 11100010 e2 227 11100011 e3 228 11100100 e4 229 11100101 e5 230 11100110 e6 231 11100111 e7 232 11101000 e8 233 11101001 e9 234 11101010 ea 235 11101011 eb 236 11101100 ec 237 11101101 ed 238 11101110 ee 239 11101111 ef 240 11110000 f0 241 11110001 f1 242 11110010 f2 243 11110011 f3 244 11110100 f4 245 11110101 f5 246 11110110 f6 247 11110111 f7 248 11111000 f8 249 11111001 f9 250 11111010 fa 251 11111011 fb 252 11111100 fc 253 11111101 fd 254 11111110 fe 255 11111111 ff $
左から順に10進数、2進数、16進数表記。2進数をよく使う理由は本著を読んでもらうとして、16進数を使う理由は、2進数(4ビット)を1文字で表すことができ、見やすくなるから。例えば、10進数の10を2進数で表すと「1010」。16進数で表すと「a」。桁数が多くなるほど、ぱっと見では2進数の場合、1と0の個数の数え間違えが起きそうだけど、16進数では2進数よりは把握しやすい、あるいは短く書くことができることが分かる。
ということで、このことが16進数をプログラミングでよく使う理由の1つだったり。
0 コメント:
コメントを投稿