情報科学概論
2002.7.2
出席に関する注意事項を説明しますので,その注意を良く聞いてから,電子メールにより出席の申告をしてください.「件名」は
gairon 7-2 attend s0240**
のように自分の学生番号を使って下さい.なお,入力ミスがあると出席として認
められないことになりますので,慎重に行ってください.文
字はすべて1バイト文字 (半角英数字) です.途中に入るスペースは一度に一個だけと
してください.スペースは全部で3個です.また,**の部分は自分の学生番号の下二桁
です.
Rubyはテキスト処理に威力を発揮するスクリプト言語なのですが,数値計算に用
いることも別に問題ありません.特に,後期から始まるC言語の授業は数値計算
を通してCを理解することが目的とされているので,その少し前に学習しておく
のも予習としてうってつけでしょう.
さて,ではどのようなスクリプトが良いのか,となると,今後も頻繁に使われる
ことが予想される定積分を求める例がまず,考えられます.つぎに,整数論とし
ては非常に有名なユークリッドの互除法を利用した最大公約数の例が挙げられま
す.
まず最初に示すのは非常
に単純な関数の定積分ですが,自分で中身をいじるとそれなりの関数も計算でき
るようになります.ここでは関数f(x)=x^2について考えてみましょう.
まずは,定積分の概念ですが,考える範囲についての関数の値を連続的に足しあ
わせて面積を求めるようなものです.一番単純に考えると,下の図1に示す様に棒グラ
フの面積を足しあわせることにより計算できます.
図1 棒グラフによる面積近似
それをスクリプトにしたのが,以下の例です.ここではxの値が0から2
までの範囲で積分します.
ここでは,積分範囲を10の領域に分けて足しあわせることとしてみました.また,
関数を自分で定義するための def 構文が使
用されています.簡単な使用法なので別段説明は不要
でしょう.
for 文においては,順番に変数の値を1ず
つ増やすことしか出来ないので,増分の設定には注意
が必要です.ここでは,Δずつ増えていくので,ルー
プの中の式の引数は変数×Δの形式となっています.
実際の定積分は自分で計算してみれば分かるように
8/3です.上記のスクリプトの実行結果は2.28であり,
だいぶ精度が悪いようです.試しに n の値を
増やしていくとどうなるか,実行してみましょう.
のようにスクリプトを変更すると自分で楽にnの値を指定できるようにな
ります.
上のスクリプトの精度が悪いのは実際には下の図2のように高さに問題のある棒グ
ラフで近似したからです.
図2 棒グラフ近似の精度の悪さの原因
次の図3のように台形で近似して面積を足しあわせるとだいぶ正確になりそうで
す.
図3 台形近似の概念図
実際にこれはSimpsonの台形公式というもので,数値計算で良く用いられる方法
です.台形の面積は,(上辺+下辺)*高さ/2となるので,
そうなるようにスクリプトを変更したものが以下の例
です.
この場合の計算結果はn=10に対して2.68であり,かなり改善されている
ことが分かります.n をさらに増やしてみるとどうなるか,試してみま
しょう.
最大公約数を機械的に求める方法は古くから「ユークリッドの互除法」として知
られています.ここでは,それを利用して、二つの正の整数の最大公約数と最小
公倍数を求めることを考えてみましょう.
2つの整数があるとき,まず,大きな数を小さな数
で割ります.そのとき,割りきれると小さな数が最大公約数になります.割りき
れなかった場合ですが、その余りに着目してみましょう.今,整数256と576の最大公約数を求めることを考えます.
576 ÷ 256 = 2 余り 64
となります.書き換えると、
576 = 256 × 2 + 64
です.公約数と言うからには両辺を割りきれるわけですが、576も256×2も割り
きれますから、64も割りきれることになります.そうなると、今度は256と64の
最大公約数を求める問題にすり変ります.そのために、また,同じ作業を繰り返
すわけで、256を64で割ることを試みます.
256 ÷ 64 = 4 余り 0
となって割りきれました.と言うことは、256と64の最大公約数は64であり,そ
れがそのまま576と256の最大公約数と言うことになります.他の一般的な場合に
ついてもこの手順を繰り返していけば出来そうです.
上の方法では、最初は与えられた2つの数どうしの割り算だったのが、割った数
が割られる数に、余りが割る数にと変更されていきます.割りきれるまでひたす
らそれが繰り返されます.ということは,余りが0になるまで、while
ループを回すことと、変数を次々置き換えていくことがポイントとなるでしょう.
これは,自己代入とかではなく、実際に変数を置き換えていくことで実現させま
す.
上の結果から次のようなスクリプトが考えられます.
手順としては、コマンドライン引数で二つの整数を与えます.二つの数の大小関
係をまずチェックして大きい方を a とし小さい方を b とし
ます.
先ほどのように、割り算を行いますが、ここで,変数の置き換えが行われていき
ます.そして,再び割り算が行われ、余りが0になるとループを終了します.
出力行にある G.C.D. とはGreatest Common Divisorの略です.
最大公約数が分かると最小公倍数も分かります.そのため,手順としてはまず最
大公約数を求めることから始まります.それには上のスクリプトがそのまま使用
できます.最大公約数Gが分かると,二つの整数IとJにつ
いて次のようなことが分かります.
I = m G
ここで,mおよびnは正の整数.すると,最小公倍数Lは
L = m n G
として求まります.あとはこれをスクリプトにするだけです.最小公倍数を
L.C.M. (Least Common Multiple) として同様に求めるスクリプトを考えて
みましょう.
他にも,数値計算で作業が簡単になる例はたくさんあるので必要に応じて
自分で試してみるのがおもしろいかもしれません.ただし,解析的な計算(たと
えば導関数を求める様なケース)は計算機は苦手です.あくまで,数値計算が楽
に出来る,ということを覚えておいた方がよいでしょう.(もちろん,解析的な
計算が出来るようなプログラムもありますが,とりあえず無いものと思っておく
方が幸せでしょう.)
上で紹介した手法を利用して自分で応用してみましょう.
授業の終りに宿題 (AクラスとBクラス別々) について説明しますので,アナウンスに注意してください.
#integral.rb
x0 = 0.0
x1 = 2.0
n = 10.0
delta = (x1 - x0) / n
integral = 0.0
def f(x)
x**2
end
for xx in 0..n-1
integral += f(xx * delta) * delta
end
printf ("Integral = %f\n", integral)
n = ARGV[0].to_f
#trapezoid.rb
x0 = 0.0
x1 = 2.0
n = 10.0
delta = (x1 - x0) / n
integral = 0.0
def f(x)
x**2
end
for xx in 0..n-1
integral += (f((xx + 1) * delta) + f(xx * delta)) * delta / 2
end
printf ("Integral = %f\n", integral)
#gcm.rb
a = ARGV[0].to_i
b = ARGV[1].to_i
if a < b
c = a
a = b
b = c
end
while b != 0
r = a % b
a = b
b = r
end
print "G.C.D. = ", a, "\n"
J = n G
ページトップに戻る