基数変換とか

基数

さて、何やらさらりと“基数”という言葉が出てきています。
一般的な用語といえばそうなのですが、聞いたこともないという方も居そうなので補足します。
まずは用語辞典をひいてみましょう。

基数 【radix
数値を表現する際に、各桁の重み付けの基本となる数。我々が普段している10進数では、10倍ごとに桁が上がっていくので、基数は10である。2進数、8進数、10進数、16進数の基数はそれぞれ2、8、10、16である。

読めばなんとなくわかりますね。別段難しいことではないようです。
それでは、この基数を相互に変換することを考えてみます。

位取り記数法

基数を変換する――というだけでは少々曖昧な気もするので、その前に知っておきたいことがあります。
それが、“位取り記数法”という名称です。
位取り記数法

位取り記数法(くらいどりきすうほう)は、数の表現方法の一種で、適当な自然数 N >1を指定して N 種類の記号(数字)を用意し、それを列べることによって数を表すための規則である。

位取り記数法で指定された自然数 N をこの記数法の基数といい、基数が N であるような位取り記数法を「N 進法」「N 進記数法」という。N 進法では、N 種類の数字からなる記号列において、隣り合う上位の桁に下位の桁の N 倍の意味を持たせる位取りによって数を表現する。

とまぁ小難しくかいてありますが、実はなんのことはなくて、普段普通の人がアラビア数字を使って数値を表記している場合、この“位取り記数法”という表現方法を用いています。
要するに普通の書き方、です。そんな説明でいいのかわかりませんが。
そして、先ほど調べた“基数”についても改めて解説されています。
このあたりを踏まえると、普段我々が使っている数の表記法は『基数を10とした位取り記数法』である、ということなのだと思います。
そして、この位取り記数法のなかで基数を別の数にすること――これが、“基数変換”になります。

10進数ってなんなのか

位取り記数法を意識したうえで、慣れ親しんだ10進数について見直してみます。
たとえば、次のような数値があります。

1234

なんの変哲もありません。「この数値はなに?」と尋ねられれば、「せんにひゃくさんじゅうよん」と問題なく答えて頂けるでしょう。
実はこの「せんにひゃくさんじゅうよん」という読み方がちょっとしたポイントだったりします。
このように数字同士をくっつけて表記し、さらに「数値」は何か、と聞かれた場合に「いちにぃさんよん」と答える方は……たまにしか居ません(と思います)。


しかし、確かに数字をひとつひとつ分解すれば、単に「1と2と3と4」が順番に並んでいるに過ぎません。
にも関わらず、自然に頭の中では「これはせんにひゃくさんじゅうよんだろ……」と解釈されているはずです。
このとき、「1と2と3と4」は額面どおりの値ではありません。
「1→実は千」であり、「2→実は二百」「3→実は三十」「4→実はも何も四」という風に各数字に対して、「ある計算」が施されてしまっています。
このとき、どのようなルールに則って計算されているのかというと、

ある桁の数字の値 × {10の(桁 − 1)乗}

という計算です。
たとえば先ほどの「1234」における「2」とは、

2 × {10^(3 − 1)}
→ 2 × 100
→ 200

という計算から、実は「二百」という数値であることがわかります。
当たり前といえば当たり前すぎる話ですが、このときに掛けられる『10の(桁 − 1)乗』のことを、各桁の“重み”といいます。
これは、位取り記数法の裏に隠されている暗黙の値です。
では、なぜこの値は『10の(桁 − 1)乗』になるのでしょうか。
それはいうまでもなく10進数は10個の集まりで一桁繰り上がるから、です。
ということは、もしも

1234

が実は10進数ではなく16進数だったとしたら、各桁の値には『16の(桁 − 1)乗』が掛かることになるわけです。
というわけで実際に計算してみると、

1234(16) → 1 × {16~(4 - 1)} + 2 × {16^(3 - 1)} + 3 × {16^(2 - 1)} + 4 × {16^(1 - 1)}
         → 1 × 4096 + 2 × 256 + 3 × 16 + 4 × 1
         → 4096 + 512 + 48 + 4
         → 4660

という具合です。
そして実はこれこそが、N進数から10進数への基数変換のやり方になります。
N進数の各桁には『Nの(桁 − 1)乗』の重みがかかりますので、そこだけうまく置き換えて同じように計算するだけで10進数への変換は楽々できてしまいます。
慣れれば簡単なので、経験のない方は2進・8進・16進あたりから10進に変換する練習をしておくといつか役に立つかもしれません。少なくとも、基本情報処理などの資格取得には役立つと思いますw
検算には、Googleの電卓機能(http://www.google.com/help/calculator.html)を使ったり、[ファイル名を指定して実行]で「calc」として、関数電卓を利用すると良いですね。


10進数以外への変換は、また別の機会に書きます。


因みに、こういう話題に興味を持ったぜ、という方には『Write Great Code』という書籍が個人的にはおすすめです。
まつもとさん繋がり、というあたりも重要です。

Write Great Code〈Vol.1〉ハードウェアを知り、ソフトウェアを書く

Write Great Code〈Vol.1〉ハードウェアを知り、ソフトウェアを書く

リテラルその2

前回に引き続き、リテラルについてです。
今日は数値リテラルを学びます。

数値リテラル

まずは公式サイトのリファレンスを確認しましょう。
数値リテラル


なんかもう、さすがにこれを見たら十分でしょう、という気がしないでもないですが、せっかくなので表にしてみます。
今回は数値リテラルのうち、整数と浮動小数点数のみを取り上げます。

整数 10進表現 123
-123
0d123
16進表現 0xffff
2進表現 0b1011
8進表現 0377
0o377
浮動小数点数 1.23
1.2e-3

やはり一番自然なのは、整数ならば「123」という書き方ですし、小数ならば「1.23」みたいな形式ですね。
ですので、たぶん特別な理由が無い限りは最も自然に思える書き方をしておけば良いのだと思います。

一応、すべての書き方を試すコードを作って実行してみます。

puts('■10進整数\n')
puts(123)
puts(-123)
puts(0d123)

puts('■16進整数')
puts(0xffff)

puts('■2進整数')
puts(0b1011)

puts('■8進整数')
puts(0377)
puts(0o377)

puts('■浮動小数点数')
puts(1.23)
puts(1.2e-3)

↓実行結果

■10進整数\n
123
-123
123
■16進整数
65535
■2進整数
11
■8進整数
255
255
■浮動小数点数
1.23
0.0012

あれ、実行結果は全部10進数表記なんですね……
取り敢えずその辺は良いでしょう。とにかくこのような表記方法で、ソースコードの中で数値を表現することができます。
文字列リテラルのように特別な記号で修飾するなどの処理は基本的に必要ありませんので、特に難しくはないと思います。
以上です。


……と、軽く流したいところですが、そうもいきません。
このコードでは、見覚えの無い関数らしきものを利用しています。適当に流さずに、ちゃんとリファレンスを確認してみます。
puts
説明と実行結果を見比べて頂けると思うのですが、今回のコードでは出力時に"\n"を記述していません。
にも関わらず一回の出力毎に改行されているのがputsの働きだったりします。
また、putsのサンプルコードには次のように書かれています。

puts "foo", "bar\n", "baz"

いままでのものと違って、関数名の隣に小括弧がありません。
実はRubyでは、『関数(メソッド)に対する引数が明らかであるとき、小括弧を省略して記述することができる』、という特徴があります。
ですので、上のコードも次のように記述可能です。

puts '■10進整数\n'
puts 123
puts -123
puts 0d123

puts '■16進整数'
puts 0xffff

puts '■2進整数'
puts 0b1011

puts '■8進整数'
puts 0377
puts 0o377

puts '■浮動小数点数'
puts 1.23
puts 1.2e-3

すっきりしました。
人の目からみてもこれは明らかだろ、という場合には積極的に省略してしまってよさそうです。

10進数以外で表示したい!

まぁ、どうしてもそういう要求が出てくることもあると思います。
少なくとも、整数値に関してはその要求を簡単に満たす方法が用意されているようです。
詳しい内容は次回にまわすとして、実際のコードだけ示しておきます。

puts '■10進整数\n'
puts 123.to_s(16)  # 16進表記
puts -123.to_s(8)  #  8進表記
puts 0d123.to_s(2) #  2進表記

puts '■16進整数'
puts 0xffff.to_s(16)

puts '■2進整数'
puts 0b1011.to_s(2)

puts '■8進整数'
puts 0377.to_s(8)
puts 0o377.to_s(8)

↓実行結果

■10進整数\n
7b
-173
1111011
■16進整数
ffff
■2進整数
1011
■8進整数
377
377

ポイントの部分はこんな形式になっています。

<数値リテラル>.to_s(<基数>)

この基数の値を変更すれば、3進数だろうが12進数だろうが変換することが可能です。

リテラル

消えたダブルクォーテーション

前回学習したことから、

print("Hello, world")

という文は「"Hello, world"を表示してください」という命令だということがわかりました。


ところが、このプログラムの実行結果はたしか

Hello, world

でした。
大体よさそうなのですが、「Hello, world」を囲む""(ダブルクォート:二重引用符)が消えてなくなってます。
これはいったいどういうことなのでしょうか。

文字列リテラル

実は、この""で囲まれたものは、“文字列リテラル”という存在になります。
Rubyリファレンスマニュアルの該当部分を確認してみましょう。
リテラル
文字列リテラル

リテラルとは

数字の1や文字列"hello world"のようにRubyのプログラムの中に直接記述できる値の事をリテラルといいます。

ふむ。
一応、元々の言葉の意味も調べてみます。
literal

literal
【名-1】 誤植{ごしょく}、誤字{ごじ}
【名-2】 《コ》直定数{ちょく ていすう}
【形】 文字{もじ}どおりの(意味{いみ}の)、逐語的{ちくごてき}な、文字{もじ}の、融通{ゆうずう}の利かない、事実{じじつ}に忠実{ちゅうじつ}な、想像力{そうぞうりょく}に欠けた、味気{あじけ}ない、四角四面{しかく しめん}の

「文字通りの意味の」というのがそれらしい感じですね。


これはつまりどういうことなのでしょう。実例で考えてみます。
たとえば、今までの「Hello, world」ではなくて「print」と出力してみたい場合の正解は、

print("print")

こうなります。
もし、これを

print(print)

と書いてしまったらどうなるでしょうか。
書いた当人としては「print」と出力したくて書いたのですが、考えてみるとprintというのは関数(厳密にはメソッドとやら)です。
ですから、これだと「print関数(の戻り値)」を出力します、という風に読めてしまうわけですね。
それでは困るので、これは「関数の名前としてのprint」ではなく、「ただの文字の並びとしてのprint」です、ということが明示できなければいけません。それを実現するのが、“文字列リテラル”という存在なのです。

文字列リテラルのつくりかた

それでは文字列リテラルについて引用してみます。

文字列はダブルクォートまたはシングルクォートで囲まれています。ダブルクォートで囲まれた文字列ではバックスラッシュ記法 と式展開(後述)が有効になります。シングルクォートで囲まれた文字列では、\\(バックスラッシュそのもの)と \'(シングルクォート)、行末の\(改行を無視します) を除いて文字列の中身の解釈は行われません。

%記法 による別形式の文字列表現もあります。

……だ、そうです。
つまり。

  • ダブルクォートまたはシングルクォートで囲まれる
  • ダブルクォートで囲まれた場合
    • バックスラッシュ記法が有効
    • 式展開が有効
  • シングルクォートで囲まれた場合
    • 基本的に文字列の中身の解釈は行われない
    • ただし、\\・\'・行末の\は例外
  • ダブルクォート、シングルクォートを使わない%記法というものもある

ということで、最初の定義を最後の最後で覆してくれました。
%記法についてもそれなりに見ておきましょう。⇒%記法
いくつか並んでますが、今回見るべきは以下の3つです。

  • %!STRING! : ダブルクォート文字列
  • %Q!STRING! : 同上
  • %q!STRING! : シングルクォート文字列

さらに、

!の部分には改行を含めた任意の非英数字を使うことができます。始まりの区切り文字が括弧(`(',`[',`{',`<')である時には、終りの区切り文字は対応する括弧になります。括弧を区切り文字にした場合、対応が取れていれば区切り文字と同じ括弧を要素に含めることができます。

ということらしいです。
結局のところ、文字列リテラルを表現する方法は5通り*1あるのですね。*2
ためしに全部使ってみます。

print("北海道")
print('日本ハム')
print(%!ファイターズ!)
print(%Q+日本一+)
print(%q(おめでとう!))

↓実行結果

北海道日本ハムファイターズ日本一おめでとう!

見事な時事ネタです。


さてさて、このように書き方は5通りですが、その解釈のされかたは結局ダブルクォート系とシングルクォート系の2つです。
ではこの2つの解釈の違いを確認してみましょう。
先ほど文字列リテラルについて引用した際に確認しましたが、この2つの違いは

  • バックスラッシュ記法
  • 式展開

の2点が有効であるかどうか、という話に尽きるようです。
このうち、式展開については諸々の都合により後回しに……。
今回はバックスラッシュ記法についてのみ確認してみましょう。

バックスラッシュ記法

=>バックスラッシュ記法
\t、\n、\r……と、頭に\が付いた文字が並んでいます。
私の環境で見る限り、バックスラッシュには見えないのですが、実はこれにはワケがあります。

バックスラッシュは約物の一つで、\のような形をしている。バックスラッシュとはスラッシュ ( / ) の逆という意味である。/に比べれば、自然言語ではあまり使われることのない記号である。

ASCIIのバックスラッシュ (0x5C, 5/12) はJIS X 0201では円記号であるため、日本のコンピュータや日本語のフォント・OS環境ではバックスラッシュが円記号として表示されるものが多い。

ということで、元来バックスラッシュで使われていた文字コード番号が、日本の環境では円記号として使われている場合が多いのです。
そんなわけなので、ひとまずは『バックスラッシュ ⇒ 円記号』と脳内置き換えしておいてもなんとかなるような気がします。


表示の問題は良いとして、そもそもこれらはどのような役割を持つものなのでしょうか。
実はこれら(\tや\nなど)は『バックスラッシュ(円記号)+文字』で1文字分のデータを表します。そして何故頭にバックスラッシュが付いているのかというと、これによって実際の文字では表現しきれない特殊な文字を表すことができるのです。
具体的にはリファレンスマニュアルにあるとおりで、例えば、

\t
タブ(Tab)
\n
改行(New line)
\r
キャリッジリターン(復帰:carriage Return)

などなどです。
このようなものを文字列リテラル内に含めることで、特殊な文字の出力を表現できるのです。
試しにこんな風に書いてみると、

print("シ\n")
print("\tン\n")
print("\t\tジ\n")
print("\t\t\tラ\n")
print("\t\t\t\tレ\n")
print("\t\t\t\t\tナ\n")
print("\t\t\t\t\t\t〜\n")
print("\t\t\t\t\t\t\tイ")

↓実行

シ
	ン
		ジ
			ラ
				レ
					ナ
						〜
							イ

こうなります。
全部を一つの文字列にしてしまっても大丈夫。

print("シ\n\tン\n\t\tジ\n\t\t\tラ\n\t\t\t\tレ\n\t\t\t\t\tナ\n\t\t\t\t\t\t〜\n\t\t\t\t\t\t\tイ")

もちろん、%記法を使ってこんな風にしてもOKです。

print(%!シ\n!)
print(%Q!\tン\n!)
print(%!\t\tジ\n!)
print(%Q!\t\t\tラ\n!)
print(%!\t\t\t\tレ\n!)
print(%Q!\t\t\t\t\tナ\n!)
print(%!\t\t\t\t\t\t〜\n!)
print(%Q!\t\t\t\t\t\t\tイ!)


このようなバックスラッシュ記法はダブルクォート系の文字列リテラルでないと有効になりません。
ですので、

print('シ\n')
print(%q{\tン\n})
print('\t\tジ\n')
print(%q(\t\t\tラ\n))
print('\t\t\t\tレ\n')
print(%q[\t\t\t\t\tナ\n])
print('\t\t\t\t\t\t〜\n')
print(%q@\t\t\t\t\t\t\tイ@)

このようなシングルクォート系を利用したコードだと……

シ\n\tン\n\t\tジ\n\t\t\tラ\n\t\t\t\tレ\n\t\t\t\t\tナ\n\t\t\t\t\t\t〜\n\t\t\t\t\t\t\tイ

バックスラッシュもなにも、そのまま表示されます。


それにしても、ヒルマン監督おおはしゃぎですね。


バックスラッシュ記法はいくつかありますが、特殊文字については最初は\n・\t・\r・\bくらい知っておけば問題ないように思えます。
使われる文字も大体元の単語から取ったものだったりしますので、結びつけて覚えておくと良いでしょう。
もう一つ知っておかなければいけないのは、\xとして紹介されている「文字そのもの」を表す書き方です。これはいったいどのような場面で使われるのでしょうか?
たとえば次のような出力結果を得たいと考えます。

This site is 'Hatena Diary'.

このとき、

print("This site is 'Hatena Diary'.")
print('This site is 'Hatena Diary'.')

上記のようなコードを書いてしまうと……

parse error, unexpected tCONSTANT, expecting ')'
print('This site is 'Hatena Diary'.')
                           ^
warning: parenthesize argument(s) for future version
parse error, unexpected ')', expecting $
print('This site is 'Hatena Diary'.')
                                     ^

こんな感じのメッセージが出て、正しく実行できません。問題は、2行目のシングルクォーテーション版にあります。
''で囲まれた部分が文字列リテラルになるので、このコードの場合だと

print('This site is 'Hatena Diary'.')

赤字で示した部分のみが文字列リテラルとして解釈され、その間が不正な文章になってしまいます。
同じように、

print("This site is "Hatena Diary".")

というように""が入れ子になってしまっている状況でも同様の問題がおきます。

print("This site is "Hatena Diary"'.")

このような状況に対応するために、\xを利用します。
つまり、シングルクォートやダブルクォートを『文字列を定義するための特別な記号』として扱わずに、単なる文字として認識して欲しい、と明示するわけです。

print("This site is \"Hatena Diary\".")
print('This site is \'Hatena Diary\'.')

このように「ただの文字だよ」と示したい文字の前に\を付加することで、特別な意味を打ち消すことができます。


あるいはバックスラッシュを使わずに、

print(%Q!This site is "Hatena Diary".!)
print(%q!This site is 'Hatena Diary'.!)

などと%記法を使っても書けます。
引用符が入り混じるような文字列の場合は、こちらの方が便利かもしれません。

文字列リテラルの使いわけ

以上のような特徴を踏まえたうえで、実際の場面ではどの方法で文字列リテラルを定義すれば良いのでしょうか。
現在の段階では、下図のような判断基準を持ち出すことができそうです。

実のところ、取り敢えずダブルクォーテーション使ってれば何とかなる気はします。
でも、たまにはちょっと意識しておかないと忘れてしまいそうなので、気をつけましょう。

まとめと練習問題

今回は、こんなことを学びました。

  • プログラム中に直接記述する「そのままの値」をリテラルと呼ぶ
  • 文字列リテラルの定義方法は5つある
    • ""ダブルクォーテーション
    • ''シングルクォーテーション
    • %!!
    • %Q!!
    • %q!!
  • 解釈の違いにより、2つの種類が存在する
    • 式展開、バックスラッシュ記法が利用できるか否かで違いが現れる
  • 特殊文字などを表現するためにはバックスラッシュ記法を使う
問題

次の出力を行うプログラムを作成してください。
なお、各行の間には1つ空行があり、2行目の先頭にはタブが1つ含まれています。

リーグ優勝、'日本一'

	そして……

次は"アジアの頂点"へ!
記述例

*1:もちろん、%記法の場合は任意の非英数字が使えるのでバリエーションはいくつかありますが

*2:ヒアドキュメントはひとまず置いておきます

続きを読む

昨日の復習

昨日はようやくRuby言語の学習を始めることができました。
まずは「Hello, world」と出力するプログラムを読み解こうとしています。
その中で、昨日学んだことを改めて書き出してみます。

  • Rubyには関数は存在しない
    • Kernelモジュールで定義されたメソッドを、特別に組み込み関数と呼ぶ
  • 関数とは、ある値を受け取って、定められた処理を施して結果を返すブラックボックスみたいなもの
    • 関数が返す結果を戻り値(返り値)と呼ぶ
    • 関数に渡す値を引数(ひきすう)と呼ぶ
      • 引数は関数のあとに続く小括弧の中に記述される
  • printは引数の値を出力する関数


と、こんなところでしょうか。

Hello, worldを読む

RDTを試した際、次のようなコードを書きました。

#
# 由緒正しいハローワールド
#

print("Hello, world")

まずは、これが一体なんだったのか、というところから見ていきます。
ちなみに、このプログラムを実行した結果は、

Hello, world

というメッセージが表示されるだけのものです。
しかし、これはかのK&Rに発端を成し、以来プログラミングを志すものの第一歩としてイニシエーション的な役割を持つ、世界共通の伝統的プログラムなのです!
……というのが大げさかどうかは寡聞にして知りません。

続きを読む

RDTを試す

本格的にRubyを学び始める前に、簡単にRDTでのプログラム作成の流れを確認してみます。


まず、RDTをインストールしたEclipseを起動します。
デフォルトではJavaの開発に向いた構成になっていますので、これをRDTが用意してくれているRuby向けの構成に変更します。

右上の、『Java』がハイライトされている部分をクリックして、でてきたリストから[その他]を選択します。

ここで名称が出てきましたが、「○○作業向けの画面構成」のことを“パースペクティブ”と呼ぶようです。
[Ruby]を選択して、[OK]を押します。

画面構成が変わり、右上ではRubyがハイライトされていることが確認できます。
これで、RDTが用意してくれた標準のRubyパースペクティブに変更されたことになります。

続きを読む

RDTインストール

Ruby統合開発環境に憧れて、RDTのインストールに挑戦したいと思います。
RDTのインストールのためには、以下のポイントを押さえる必要があります。

というわけで、下から順に解決していきます。

Java実行環境のインストール

まずはEclipse実行のために必要な、Javaの実行環境を構築します。
とはいえ、現在前提としているWindows XP環境であれば最初からJavaが実行できる状態にはなっています。
Javaの実行が可能な状態かどうかは、以下の手順で確認できます。


コマンドプロンプトを起動(覚えてますか?)→java -version と入力してエンターキー押下


Javaが実行可能な状態ならば、これによってインストールされているJavaのバージョン情報が表示されるはずです。
インストールされていないようならば、Java SE Downloadsからダウンロードしてきてセットアップします。

Eclipseのインストール

公式サイトより、Eclipseをダウンロードしてきます。

Eclipse.org home
http://www.eclipse.org/
続きを読む