授業資料/04 の変更点


#contents

* 前回の課題について [#b371f0a2]

前回は「与えられた数が素数かどうか判定するプログラム」を書くのが課題だった.
それについて,いくつか例を示して解説をしておこう.

** 最も素朴なプログラム [#v0e4f70e]
まずは,素数の定義に従って 2 から (その数-1) までで割れるかどうか全部チェックするという,オーソドックスかつ特別な工夫を凝らさずにプログラムをした場合だ(説明のために,行に番号をつけて表示している).
これは,最初に n が素数と仮定して,その n を割れる数を探していく,というアルゴリズムである.
#highlighter(language=ruby,number=on,cache=on){{
include Math

n = 133
isPrime = "is a prime number."

for i in 2..(n-1) do
  if (n % i == 0) then
    isPrime = "is not a prime number."
  end
end

p n 
p isPrime
}}
&ref(/materials/warning.png); for 文が 2..(n-1) となっているのは,i が 2 から (n-1) までの範囲を変化するという意味である.
&ref(/materials/warning.png); for 文の中に if 文が入っている.こうしたことはたいてい可能なので,思いついたら試してみよう.
&ref(/materials/warning.png); if 文の else節が省略されている.こうしたことも可能なことが多いので,やはり思いついたら試してみよう.

** 少し巧妙な? プログラム [#k6244bcf]
本質は変わらないが,次のようなものもある.
#highlighter(language=ruby,number=on,cache=on){{
include Math

n = 133
isPrime = 1

for i in 2..(n-1) do
  isPrime *= (n % i)
end

p n
if (isPrime == 0) then
    p "is not a prime number."
  else
    p "is a prime number."
end
}}
n がある数 i で割り切れたときだけ n % i がゼロになることを利用して,(n % i) をどんどん掛けていって,ゼロになっているかどうかをチェックするという方法である.
&ref(/materials/warning.png); *= の部分は,「左辺の変数に右辺をかけてから代入する」という意味である. isPrime = isPrime * (n % i) と書いても良い.

** 割る数の範囲を少なくしたアルゴリズム [#ea72e0bb]

良く考えてみると,n を割りきれるかどうかを調べる整数 i は √n 以下までみれば十分である.
(例えば,21 = 3 * 7 = 7 * 3 は 3 で割れることがわかれば十分)
よって,「探索範囲」はずっと小さく出来る.この考え方で改良したのが次のプログラムになる.
#highlighter(language=ruby,number=on,cache=on){{
include Math

n = 133
isPrime = "is a prime number."

upper = sqrt(n).floor
for i in 2..upper do
  if (n % i == 0) then
    isPrime = "is not a prime number."
  end
end

p n 
p isPrime
}}

** 割る数の範囲をもっと少なくしたアルゴリズム [#yc9a3544]

考えてみると,上のプログラムでは 2 で割れるかどうか確かめたあと,4 でも割れるかどうかチェックするなど,「明らかに無駄なチェック」がたくさん入っている(4で割れるなら 2 でも割れるじゃん).
そう考えてみると,素数を小さい順に列挙していって,それを使ってチェックする方が早い…など,こんな単純な方法にさえいろいろ改良の余地はある.


** その他 [#ye3ca722]

ある整数が素数かどうかの判定をどう行うかのアルゴリズムについては実は多くの研究がある.
興味のある人は(google scholar などで "primality test" という単語で)探してみるとよいだろう.

** 大事なこと [#wffdfe27]

どうだろうか.まずは動くプログラムを自分で書けただろうか.
うまくいかなかった人は,まずは「真似る」ところからでよいので,すこしずつ習熟しよう.

* インプット(入力) [#f5e1d3d8]

さて,プログラムが「情報を処理する」機能を果たすには,情報の入出力機能がないとまずい.
これまでは入力すべきデータをプログラム内に書き,出力は画面に出してそのまま,という方法できたがこれでは不便すぎる.

そこで,まずはインプット,すなわち,プログラムにデータを渡す方法について学ぼう.
インプットを行う方法は,大雑把にいって,

- 起動時にパラメータとして与える
- 「標準入力」という特別に定まった入力方法に対応する
- ファイルから読み込む
- プログラムが動いている時にインタラクティブにデータを与える

など,様々な方法があり,それぞれに向き不向きがある.

いきなりたくさん学ぶと混乱するだろうから,今回は一つだけ学ぼう.

** 起動時にパラメータとしてデータを受け取る: ARGV 変数 [#r754193b]

起動時にパラメータとしてデータをプログラムに与えることができる.
このとき,プログラム側では
CENTER:&size(24){''変数 ARGV[0] で一つ目,ARGV[1] で二つ目, (以下同様) ''};
CENTER:&size(24){''の起動時パラメータを受け取れる.''};

&ref(/materials/notes.png); といっても,意味がよく分からない人もいるだろうから,サンプルを動かしてみよう.
まず,次のプログラムを例えば ''sample.rb'' というファイル名で保存したとして,
#highlighter(language=ruby,number=on,cache=on){{
include Math

p "The first parameter is "
p ARGV[0]

p "The second parameter is "
p ARGV[1]
}}
として,
  ruby -w sample.rb aaa bbb
としてプログラムを動かしてみよう.
これは,このプログラムを動かすときに 1つ目のパラメータに ''aaa'' を, 2つ目のパラメータに ''bbb'' を与えたことになる.
すると,次のような出力が得られるはずだ.
> "The first parameter is "
> "aaa"
> "The second parameter is "
> "bbb"

これを見ると,プログラム側で ''aaa'' と ''bbb'' を受け取れていることがわかる.
&ref(/materials/warning.png); ruby では " (ダブルクオーテーション)で囲った部分は ''文字列'' である.
&ref(/materials/warning.png); ダブルクオーテーションで囲まれているこの結果例を見るとわかるが,ruby では
CENTER:&size(24){''ARGV[0], ... は文字列として扱われる.''};

だから,数字をデータとして与えたいときは,プログラム側で対処しないといけない.
これも理解のためにサンプルを見てもらおう.
''与えたパラメータ3つを足すプログラム'' (再び ''sample.rb'' という名前だと仮定して)
#highlighter(language=ruby,number=on,cache=on){{
include Math

a = ARGV[0].to_i
b = ARGV[1].to_i
c = ARGV[2].to_i

p a+b+c
}}
として,
  ruby -w sample.rb 3 8 2
としてプログラムを動かしてみると,出力 ''13'' が得られるはずだ.

&ref(/materials/warning.png); このプログラム中の,''.to_i'' というのは,変数を整数に変換する機能だ.
&ref(/materials/warning.png); 同様に,''.to_f'' とすると実数に変換される.
このように,
CENTER:&size(24){''受け取った ARGV[0], ... が整数のつもりならば .to_i を,''};
CENTER:&size(24){''実数のつもりならば .to_f をつけて変換しておこう.''};

&br;
&ref(/materials/notes.png); では,与えられた数が素数かどうかを判定するプログラムを改良して,''判定すべき整数を起動時にパラメータとして与えられるようにしよう''.
具体的には,例えば,
  ruby -w sample.rb 133
とすると
> 133
> "is not a prime number."

などと出力されるようにしようということである.
&br;

さて,与えるパラメータの数が決まっていない場合がある.
こういうときは,プログラム側で受け取ったパラメータの個数を知ることで対処する.
具体的には,
CENTER:&size(24){''ARGV.size でパラメータの個数がわかる.''};

例えば,
#highlighter(language=ruby,number=on,cache=on){{
include Math

p ARGV.size
}}
として
  ruby -w sample.rb a b c
としてプログラムを動かしてみると,''3'' という出力が得られるはずだ.

&br;
&ref(/materials/notes.png); では,パラメータとして与えた複数の数の平均を出力するプログラムを書こう.
具体的には,例えば,
  ruby -w sample.rb 3 23 4 8 9
とすると
> 9.4

などと出力されるようにしようということである.
&ref(/materials/warning.png); この出力が ''9'' になってしまう人はどこかがおかしいので,「何が起きているのか」よく考えよう.
&ref(/materials/warning.png); 与える数がこの例のように5個とは限らない.6個でも3個でも大丈夫なようにプログラムしよう.

* アウトプット(出力) [#e1baeaf5]

データを画面にただ出すだけしかまだ学んでいないが,これでは情報処理という観点からもやはり不便だ.
そこで,少しずつアウトプットについても学んでいこう.

** (準備)すこし綺麗な出力を: print 命令 [#q8d70c90]
これまで出力は扱いが簡単な ''p'' 命令のみで行ってきたが,これは出力が整頓されていないので読みにくい場面も多い(実は ''p'' 命令はプログラマには便利な機能なのだが…).
そこで,出力結果がもう少し読みやすい ''print'' 命令について学ぼう.
使い方は簡単で,
CENTER:&size(24){'' print() の中に出力するものをカンマで区切って並べるだけ''};

でけっこう読みやすく表示される.
&ref(/materials/warning.png); ただし,''\n'' という特殊な文字列を出力したときしか出力が改行されない.
だから,気持ちとしては
CENTER:&size(24){''出力を改行したいときは print 命令に文字列 \n を入れよう.''};
だから,
CENTER:&size(24){''出力を改行したいところで print 命令に文字列 \n を入れよう.''};

ということになる.
まあ,以下のサンプルを見てみよう.
#highlighter(language=ruby,number=on,cache=on){{
include Math

a = 3.0
b = 8.0

print("a is ",a," and b is ",b,".\n")
print("Average is ", (a+b)/2, ".\n")
}}
このプログラムを動かすと,
> a is 3.0 and b is 8.0.
> Average is 5.5.

となるはずである.
&ref(/materials/warning.png); ''\'' という記号は,状況によっては ''¥'' 記号で表示されるので注意しよう.同じものだ.

ちなみに,上のプログラム例は
#highlighter(language=ruby,number=on,cache=on){{
include Math

a = 3.0
b = 8.0

print("a is ")
print(a)
print(" and b is ")
print(b)
print(".")
print("\n")

print("Average is ")
print((a+b)/2)
print(".")
print("\n")
}}
と書いても同じ出力になる.この例だとわかりにくいだけだが,このように ''print'' 命令を分割した方がプログラムしやすいこともある.

&br;
&ref(/materials/notes.png); 上で改良した「起動時に与えたパラメータの平均を求めるプログラム」を,''print'' 命令を使ってさらに改良して,出力を読みやすくしよう.
具体的には,例えば,
  ruby -w sample.rb 3 23 4 8 9
とすると
> Input: 3.0 23.0 4.0 8.0 9.0
> Average: 9.4

などと出力されるようにできればだいぶよい感じだ.
&br;

** 出力をとっておく方法: パイプ & tee [#p3f3e325]

今のところ,出力は画面に流れるだけで,いずれ見えなくなってしまう.
ファイルに出力するプログラムの機能などについては後で学ぶので,ここでは 起動時にちょっと工夫するだけで ''画面とファイルに同時に出力させる簡単な'' 方法について学ぼう.

やり方は簡単で,
CENTER:&size(24){''プログラムの起動時に''};
CENTER:&size(24){'' | tee 画面への出力を記録しておくファイルの名前''};
CENTER:&size(24){''を最後にくっつける''};

だけでよい.
まあ,例を見てみよう.例えば,
  ruby -w sample.rb 3 23 4 8 9
とすると
> Input: 3.0 23.0 4.0 8.0 9.0
> Average: 9.4

と出力されるプログラムに対して,''output.dat'' という名前のファイルに結果を記録しておきたいとする.
その場合は,
  ruby -w sample.rb 3 23 4 8 9 | tee output.dat
とするだけで,画面にも,''output.dat'' というファイルの中にも
> Input: 3.0 23.0 4.0 8.0 9.0
> Average: 9.4

という結果が出力されることになる.
&ref(/materials/warning.png); '' | tee'' は出力に使うファイルの中身をまっさらにして出力してしまう(上書きする)ため,既存のファイルに対して使うときは気をつけよう.
&ref(/materials/warning.png); ちなみに,'' | tee -a ファイル名'' という風に ''-a'' をつけて使うと,ファイルの中身に出力を「追加」してくれる. 上手に使い分けよう.

* 今日の総仕上げ [#d4782677]

これまでに学んだ知識を使って,次のようなプログラムを作り,結果を ''output.dat'' という名前のファイルに記録しよう.
そのプログラムとは,次の条件を満たすものである.

+ 起動時にパラメータとして整数 ''n'' が与えられる(大きさは 100 から 300程度を想定しよう).
+ ''2'' から ''n'' のすべての整数まで,素数かどうか判定する.
+ 判定結果を順番にすべて出力する.

具体的には,''sample.rb'' というプログラムファイルだとして,例えば
  ruby -w sample.rb 133
とすると
> 2 is a prime number.
> 3 is a prime number.
> 4 is not a prime number.
> …略…
> 131 is a prime number.
> 132 is not a prime number.
> 133 is not a prime number.

という出力が得られるものだということである.

そして,この出力結果を ''output.dat'' というファイルに記録しておけ,ということになる.

* レポート [#l7e46ce9]

本日受けた講義および行った実習について,簡単にまとめた報告をせよ.
また,総仕上げの部分で自分で書いたプログラムを報告せよ.

もちろん各自の

+ 所属(学部,学科)
+ 学籍番号
+ 学年
+ 氏名
+ 日時
+ 肝心のレポート内容(得た知見,作業について気づいたこと等も)

を書くのを忘れないように. 

* about Icons, ClipArts [#edce8428]
Some icons in this page are downloadable at [[ICONFINDER:http://www.iconfinder.net/]].

The "note" icon &ref(/materials/notes.png); designed by [[Marco Martin:http://www.notmart.org/]] is distributed with the LGPL licence,
the "warning" icon &ref(/materials/warning.png); designed by [[Alexandre Moore:http://nuovext.pwsp.net/]] with the GPL licence
and the "triangle" icon &ref(/materials/JNorth_arrow-right-sm.png); designed by [[Joseph North:http://sweetie.sublink.ca/]] is distributed with the [[Creative Commons (Attribution-Noncommercial-Share Alike 3.0 Unported):http://creativecommons.org/licenses/by-nc-sa/3.0/]] licence.

Some clip arts used in this page are downloadable at [[Open Clip Art Library:http://www.openclipart.org/]].
We deeply appreciate their superb works. With licence, they describe that "the actual clipart content on open clipart library is Public domain" in the web.

// ━┃┏┓┛┗┣┳┫┻╋


// コマンドライン入力は「行頭をブランクで始める」.
// コマンドライン出力は「行頭を > で始める」.

// 実習アイコン
// &ref(/materials/notes.png); 

// 注意アイコン
// &ref(/materials/warning.png);

// Link アイコン
// &ref(/materials/JNorth_arrow-right-sm.png);

// 大文字での強調 
// CENTER:&size(24){''ほげほげ''};

// programu source 表記
// #highlighter(language=ruby,number=on,cache=on){{}}