回答編集履歴

1 訂正

KSwordOfHaste

KSwordOfHaste score 17352

2018/06/27 13:46  投稿

回答が出そろってますけども
「N進数」なるものを普段使うことが少ないためプログラマーでない一般の人は「N進数の本質」をあまり気にしてない人が大多数だと思います。N進数の本質をよく理解できれば質問者さんの疑問は解消できます。
例えば10進数で123は
`1 * (10^2) + 2 * (10^1) + 3 * (10^0)`(ここではx^yはxのy乗と思ってください)
のことですよね・・・。10進数しか使わないことが多いので各桁の重みは1, 10, 100, 1000, ...のように「10進数で表現した数値としてゼロがi個並んだ値」という程度の理解しかしていないケースも多かろうと思いますが数学的に考えるならこれはi番目の桁の重みを10^iとするのが10進数数であり10進数の代わりにN進数にするなら重みはN^iになるということがわかっていればよいです。
さて26進数で7つのアルファベットを表すということは、各桁(0~25)をアルファベットに割り当てて、26進数で7桁の数値で表現するという意味なので`0`~`(26^7)-1`の範囲の数値が表現できればあらゆるアルファベット7つの列を表現できることになります。
`26^7 = 8031810176`ですので`0 ~ 8031810175`の範囲の数値が表現できればよいですがこれを2進数で表すと何ケタ必要かというのが要するにビット数の定義なので
`log2(26^7) = log(26^7)/log(2) ≒ 32.90307802698764`
ということで33bit必要です。ゆえに32bitだと「任意の7文字を表現するにはちょっと足りないけど概ね表現できる」と言えます。
> 7文字なら56bit数値である必要がある
これは
- N進数で表現することの本質的な意味
- 計算機の(ISO-8859-1のような)符号化方式が大雑把に言えば256進数の各桁をアルファベットとした方式であること
つまり1文字が256通りのアルファベットである符号化方式であり1文字文で8bit必要になるということ
を把握できていないことからくる誤解といってよいと思います。
---
上記のN進数の意味がきちんと把握できていて、かつ計算機言語で剰余と整数除算(数学的除算結果の小数部を切り捨てる)の機能が把握できていれば、任意の整数値とその整数値をN進数で表現した各桁との間の相互変換が考えられると思います。
例えば10進数の`123`の100の位の桁`1`はどうやれば求まるかと言えば
切り捨て(123 / 100) => 1
ですね。Pythonでこれを表現するには
123 // 100
でよいです。この桁を覗いた残り23は
123 - (123 // 100)
123 - (123 // 100) * 100
ですから、これを繰り返せば10の位が`2`、1の位が`3`であることが計算できます。これは「高位の桁から求める方法」です。
逆に剰余演算子を用いると「低位の桁から求める」ことができ、
123 % 10
が3であり、
123 - 123 % 10
が1の位を取り除いた残りの桁だけの値120になりますので120を10で割って12にし、同じことを繰り返せば10の位が`2`、100の位が`1`であることも計算できます。
ということで、N進数の各桁と全体の数値との間の相互変換は**N進数の本質さえ分かっていれば**「計算機言語の整数に関する演算子の知識」があればプログラミングできます。
```Python
alphabets = ''.join(chr(ord('a') + i) for i in range(26))
base = len(alphabets)
def alphabets_to_number(a):
   n = 0
   for c in a:
       d = alphabets.index(c)
       n = n * base + d
   return n
def number_to_alphabets(n, l=7):
   a = ''
   for _ in range(l):
       d = n % base
       a = alphabets[d] + a
   return a
print(alphabets_to_number('zzzzzzz'))        # 8031810175
print(number_to_alphabets(8031810175))       # 'zzzzzzz'
```
上記は26進数の各桁を`a`=0, `b`=1, ..., `z`=25として計算するコードですが、
`alphabets = '0123456789'`に変更すればそのまま10進数に対する計算になりますし
`alphabets = '01'`に変更すれば2進数に対する計算になります。
---
長々書きましたが「2進数」「16進数」などで検索すると「桁」と「全体の数値」との相互変換のやりかたは沢山の解説ページがヒットします。しかし本当はごちゃごちゃしているように見えて普段使っている10進数の本当の意味が分かっていれば実はなんということもない変換であることがわかる気がします。「2進数の変換方法はこう」「16進数はこう」なんて特別扱いして理解したり覚えたりする必要はないように思うのです。普段10進数の数値をどう捉えているか、つまり「わかっているようで実は10進数のことをわかっていない」ことが問題の本質ではないかと思ったりします。いかがでしょうか。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る