roy > naoya > 基礎プログラミングI > (8)16進数・ASCIIコード

(8) 16進数・ASCIIコード

[1] 2進数と16進数

2進数の必要性

コンピュータ内部では、文字も数字も写真も音楽も全て1と0の2種類の数字に置き換えられて保存されている。1と0の2種類の情報であれば、スイッチのオン/オフや、磁極の向き、光の点滅で表現することが可能となるためである。例えば、ハードディスクはS極とN極の磁化パターンにより1と0を記録しているし、CDやDVDはディスク表面に溝を彫り、そこにレーザー光を当てた際の反射光の拡散の有無により1と0を区別している。

我々が日常的に使用している10進数をコンピュータでそのまま取り扱うことを考えた場合、10種類の情報の表現方法を考えなければならず、装置の複雑化、大型化を招くことになる。

2進数の構造

2進数は0と1の2種類の数字のみを使用するため、0の次は1、1の次は1桁繰り上がって10になる。以下に10進数との対応関係を示す。右側には16進数も示す。2進数は2種類の数字のみで表現するために桁数が大きくなりやすい。コンピュータにとっては桁が多くても全く問題はないが、人間は読み間違いをする可能性がある。16進数は2進数を4桁ごとに区切り0000から1111を0からfに置き換えて表現することで、4桁を1桁で表現することができる。これにより人間が2進数を取り扱う際の間違いの軽減を目指している。

10進数を読む場合と異なり、2進数、16進数は1桁ずつ読む。

  • 10進数の10:「じゅう」
  • 2進数の10:「いちぜろ」
  • 16進数の10:「いちぜろ」
2 進 数10 進 数16 進 数
000
111
1022
1133
10044
10155
11066
11177
100088
100199
101010a
101111b
110012c
110113d
111014e
111115f
100001610

2進数と16進数

  • 0と1の2種類の数字で表現するのが2進数
  • 0から9の10種類の数字で表現するのが10進数
  • 0からfの16種類の数字で表現するのが16進数

[2] Rubyでの2進数、10進数、16進数取り扱い

Rubyでは、数値の先頭につける記号でその値が何進数であるかを指定する。

  • 接頭語なし:10進数(例えば,10,25)
  • 接頭語0b:2進数(例えば,0b1001,0b111101)
  • 接頭語0x:16進数(例えば0x1a1,0xf)

なお、何進数で指定をしても、一旦読み込まれれば全て内部では10進数で計算される。出力する際に何進数とするかは、printfの書式制御文字により指定可能である。

  • %d:10進数
  • %b:2進数
  • %x:16進数

Rubyでの2進数、16進数の取扱い

  • 接頭語に0bをつけると2進数になる(x=0b100はxに2進数の100を代入する)
  • 接頭語に0xをつけると16進数になる(x=0x100はxに16進数の100を代入する)
  • 接頭語に何もつけないと10進数になる(x=100はxに10進数の100を代入する)
  • printfの書式制御文字の%dは10進数、%bは2進数、%xは16進数

[3] 出席課題

以下は好きな数字の入力を求め、進数の変換を行うプログラムである。emacsに貼り付けて保存をした後で(ruby10.rb)、その下にある4つの数字を指定した進数に変換した結果をメールで送信する。ただし、このプログラムにはエラーがあり、このままでは上手く実行できない。エラーを修正した後で実行すること。

pメソッドを使いながら、値が正しく代入されているかどうかを確認すると、間違いを発見しやすい。

#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-

print"好きな数字を入力してください"
number = gets.chomp!.to_i

print"何進数に変換しますか(1:2進数、2:10進数、3:16進数)"
choice = gets.chomp!

if choice == 1
  printf("2進数だと%bです\n",number)
elsif choice == 2
  printf("10進数だと%dです\n",number)
elsif choice == 3
  printf("16進数だと%xです\n",number)
else
  print"やる気ないでしょ?\n"
end
  1. 1234を16進数で表示
  2. 0xb1111を10進数で表示
  3. 300を2進数で表示
  4. 0b1111001を16進数で表示

制限時間は5分。出席点は2点。提出要領は下記の通り。

  • 提出先:課題提出用メールアドレス
  • メールのSubject:ruby08
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降でまずプログラムのどこを修正したかを述べ、その後で1~4の解答を記す。

Tips:emacsでの日本語入力のオンオフはCtrl-oです

Tips:Mewによるメールの送り方はMewコマンドを参照

[4] 2進数と10進数の変換

10進数を2進数へ

10進数から2進数への変換方法

2進数を10進数へ

2進数から10進数への変換方法

[5] 16進数と10進数の変換

10進数を16進数へ

16進数から10進数への変換方法

16進数を10進数へ

10進数から16進数への変換方法

[6] 2進数と16進数の変換

2進数を16進数へ

2進数を末尾から4桁ごとに区切り、それぞれ16進数に変換する。0000は0、1111はfになる。その他の対応関係は冒頭の表を参照のこと。4桁に区切った際、先頭は4桁に満たない場合があるば、その際は左側に0を補う。

例:0b110101を16進数に変換する。

  1. 4桁ごとに区切る:「11」「0101」となる。
  2. 「11」は4桁に満たないため、先頭に0を付加し「0011」とする。
  3. それぞれ16進数に変換。「0011」は3、「0101」は5となる。
  4. これらをあわせると、0b110101は0x35となる。

2進数4桁を16進数1桁に変換する

左から「8」「4」「2」「1」として、1のところの合計を求める。例えば、2進数が1111の場合は4桁ともに1なので8+4+2+1=15となる。15は16進数でfなので、答えはf。

2進数が0101の場合は1のところは「4」と「1」なので、これらの和を求めて4+1=5となる。

4桁目3桁目2桁目1桁目
8421
例11111=8+4+2+1=15(f)
例20101=4+1=5
例30011=2+1=3

16進数を2進数へ

16進数を1桁ごとに区切り、それぞれ2進数4桁に変換する。対応関係は冒頭の表を参照のこと。変換後4桁に満たない場合は左側に0を補う。

例:0x35を2進数に変換する。

  1. 1桁ごとに区切る:「3」「5」となる。
  2. それぞれ2進数に変換。「3」は11、「5」は101となる。
  3. いずれも4桁に満たないため、先頭に0を付加し、11は0011、101は0101とする。
  4. これらをあわせると、0x35は0b00110101となる(先頭に限っては左端の00は不要なので0b110101がより正しい正解)。

16進数1桁を2進数4桁に変換する

与えられた16進数を「8」「4」「2」「1」の数字の和に変換する。使用した数字を1、使用していない数字を0とする。

例えば16進数の9は8+1なので1001、b(11)は8+2+1なので1011となる。

4桁目3桁目2桁目1桁目
8421
例1:98+11001
例2:d(14)8+4+21110
例3:54+10101

[7] ASCIIコード

コンピュータ内では文字が1と0の組み合わせに置き換えられて保存されていることはすべに述べたが、この数字の配列と文字の対応表のことを文字コード表という。

半角英数字は、0-9の数字、A-Zの大文字のアルファベット、a-zの小文字のアルファベット、?#$%@などの記号により構成されている。これだけの情報を1と0の組み合わせで表現するためにはある程度の桁数がなければならない。桁数と表現できる種類の関係は下記の通りである。

  • 1桁:21=2
  • 2桁:22=4
  • 3桁:23=8
  • 4桁:24=16
  • 5桁:25=32
  • 6桁:26=64
  • 7桁:27=128
  • 8桁:28=256
  • 9桁:29=512
  • 10桁:210=1024
  • 11桁:211=2048
  • 12桁:212=4096
  • 13桁:213=8192
  • 14桁:214=16384
  • 15桁:215=32768
  • 16桁:216=65536

半角英数字は2進数8桁で表現されている(ただし先頭の1桁は使用していないので実際には7桁)。例えば

  • Aは01000001
  • Bは01000010

となる。半角英数字の文字コードをASCIIコードという。日本語は漢字が含まれるため8桁(256通り)では表現できない。日本語を表現するためには1文字当たり16桁の2進数が用いられる。

日本語の文字コードはJISShift-JISEUCが用いられている。つまり、2進数と文字の対応表が3種類ある。時折文字化けで見られないWebページがあったり、emacsで作成したプログラムのうち日本語部分がおかしくなっている場合があったりする。これは文書やプログラムを作成したときの文字コードと表示をするときの文字コードが一致していないためである。本学ではUTF-8を文字コードとして使用している。日本語だけでなくヘブライ文字やアラビア文字などの世界中で用いられている文字を一体的に表現する文字コードで、日本語は24桁の2進数で表現されている。

ASCIIコードの表は以下の通りとなる。ここでは16進数での文字コード表記となっている。2進数で表現しても良いが、桁数が多くなるため読み間違える可能性が生じやすく、一般的にも16進数表記が用いられる。

ASCIIコード

行方向(左側)が10の位、列方向(上側)が1の位になる。例えばAは41になる。Rubyでは16進数は0xをつけるのでAは0x41と表現できる。

0行と1行(0x00~0x1F)は制御文字をあらわす。主に端末のコントロールをするもので代表的なものとして以下を挙げることができる。

  • 0x00 NUL:空文字(文字列の終端をあらわすことが多い)
  • 0x07 BEL:端末のベルを鳴らす
  • 0x08 BS:バックスペース
  • 0x09 HT:タブ
  • 0x0A LF:改行
  • 0x1B ESC:エスケープ

ASCIIコードについて

  • 半角英数字(0-9、A-Z、a-z、@#$%等の記号)と2進数の対応表をASCIIコードという。
  • 半角英数字は2進数8桁で表現される。
  • 2進数4桁は16進数1桁で表現できるため、ASCIIコード表は16進数で表記されている。

[8] 文字列と文字コード

制御文字の中にはキーボードから入力できないものがある。プログラムの中で制御文字を使用したい場合は文字コードで指定する。

文字コードに対応する文字を出力

%c:printfの書式制御文字の%cは、文字コードに対応する文字を出力する。

printf("%c", 0x07)

とすると、文字コード0x07すなわちBELが出力され、端末のベルがなる(がスピーカーがついていないと音はならない)。

文字に対応する文字コードを出力

特定の文字の文字コードを知るためには?文字.ordとする。例えばプログラム中で?Q.ordとすれば、それはQの文字コード(0x51)を書いたのと同じことになる(ordメソッドは、文字列.ordでその文字列の文字コードを返すメソッド。文字列が複数文字から構成されている場合は先頭の文字の文字コードを返す。)。これをprintfの制御文字である%x(16進数)で表示すれば、対応する文字コードが明らかになる。

ここでは、A~Zの文字コードを一覧表示させてみよう。以下のプログラム(ascii.rb)は変数charに?Aを代入している。これは、Aの文字コード(0x41)を指定したことと同義になる。その後、while-endを用いて、変数charの値を繰り返し表示している。この際、書式制御文字として%cと%xを使用している。%cを使うことで、16進数の文字コードに対応する文字が表示され、%xを使うことで、16進数の文字コードそのものを表示することができる。

なお、プログラム内ではchar += 1としているが、charには16進数の値が代入されているため、このように1ずつ増加させることが可能となる。これにより、charには次の文字の文字コードが代入された状態となる。while-endの繰り返し継続条件についても同様で、charに代入された16進数と、?Z、つまりZの文字コードである0x5aとの比較により継続有無が判定されている。

実際に実行して結果を確認しておこう。

#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-

char = ?A.ord

while char <= ?Z.ord

  printf("%c   0x%2x\n", char, char)
  char += 1
end

2文字以上から構成される文字列の文字コード

上記の方法では1文字の文字コードを調べるのは簡単でも、文字列を構成する各文字の文字コードを調べるのはやや面倒である。文字列"Koeki"を構成する"K""o""e""k""i"の各文字の文字コードを調べることを考えてみよう。ここでは配列のときと同じように[]を利用すると簡単に取り出すことができる。

printf("%x\n", "Koeki"[i].ord)

上記のようにインデックスにiを使用し、初期値を0とした上で、whileの繰り返しの中でiの値を1ずつ変更していけば構成する文字の文字コードを全て明らかにすることができる。"Koeki"[0]は先頭の"K"を指定したことになり、"Koeki"[1]は2文字目の"o"を指定したことになる。もちろん下記のように文字列を変数に代入しても同じである。これによりキーボードから入力した任意の文字列を構成する文字の文字コードを調べることができる。

a = "Koeki"

printf("%x\n", a[i].ord)

文字コードについて

  • printfの書式制御文字の%cは文字コードに対する文字を出力する。
  • ?文字.ordと書くとその文字の文字コードを書いたことと同じことになる(例:?A.ordは0x41と同じ意味)。
  • 文字列の文字コードを知る場合は、文字列[i]として文字列を配列扱いとし、インデックスを変更することで0文字目、1文字目、2文字目を順に取り出しながら文字コードを調べることができる。

[9] レポート課題

以下の5問を実施する。

  1. 0x143fを10進数に変換せよ(計算過程を示すこと)
  2. 0b10011011を10進数に変換せよ(計算過程を示すこと)
  3. 0x146 + 0x67の計算を行った結果を10進数で示せ(計算過程を示すこと)
  4. 0x146 + 0x67の計算を行った結果を2進数で示せ(計算過程を示すこと)
  5. キーボードから入力した任意の半角英数字で構成される文字列を文字コード(16進数)に変換して出力するプログラム(report7.rb)を作り、ローマ字で書いた自分の氏名を入力して実行結果を確認せよ。

問1から問4の計算過程のうち例えば、10進数を2進数に変換する場合の計算過程は以下のように書くことができる。

2) 100 0
  ----
2)  50 0
  ----
2)  25 1
  ----
2)  12 0
  ----
2)   6 0
  ----
2)   3 1
  ----
     1
  • 提出先:課題提出用メールアドレス
  • 提出期限:第1提出期限、第2提出期限を設定
  • メールのSubject:report07
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
  1. 問1の計算過程と解答
  2. 問2の計算過程と解答
  3. 問3の計算過程と解答
  4. 問4の計算過程と解答
  5. 問5のプログラム
  6. 問5のプログラムの説明
  7. 問5の実行結果
  8. 感想
  9. 参考文献
  10. 作成したプログラムの添付

  • 採点基準:期限内提出点(2点)、問1~問4(各1点)、問5はプログラムが1点、説明が1点とする。問1~問4は計算過程が示されていない場合は減点する。
  • 他人のレポートを丸写しした場合は、写した側、写させた側共に0点とする。
  • わかりにくい説明や、Webページを単にコピー&ペーストしただけの説明は減点する。一度読み直してから提出すること。
  • 驚異的に良くできているレポートについては満点の8点を超える得点をつけることがある。
  • よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。