問13: 1 から n までの間にある素数を列挙するプログラムを作ってみましょう。 n はプログラム中に書き込むことにして、とりあえず 100 とします。
# いわゆる「エラトステネス(Eratosthenes)のふるい」による計算
n = 100
a = [false, false] # 0,1 は素数ではない(合成数である)
for i in 2 .. n do # 2 から n まで順にチェックする
if a[i] == nil # a[i] が素数か合成数か未チェックである
a[i] = true # i は素数である、と a[i] に記録する
k = 2*i # ↑
while k <= n do # ↑
a[k] = false # 素数 i の倍数 k は合成数である、と a[k] に記録する
k += i # ↓
end # ↓
end
end
for i in 0 .. n do # i を 0 から n まで動かしたとき
if a[i] # もし a[i] が true である(つまり i が素数である)
puts i # ならば i を表示する
end
end
------------------------------------------------------------------------------------------
n = 10 の場合 (N -> nil, T -> true, F -> false)
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, N, N, N, N, N, N, N, N, N, ...]
i = 2, a[i] == nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, N, N, N, N, N, N, N, N, ...]
a -> [F, F, T, N, F, N, F, N, F, N, F, ...]
i = 3, a[i] == nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, N, F, N, F, N, F, ...]
a -> [F, F, T, T, F, N, F, N, F, F, F, ...]
i = 4, a[i] == false != nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, N, F, N, F, F, F, ...]
i = 5, a[i] == nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, N, F, F, F, ...]
i = 6, a[i] == false != nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, N, F, F, F, ...]
i = 7, a[i] == nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, T, F, F, F, ...]
i = 8, a[i] == false != nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, T, F, F, F, ...]
i = 9, a[i] == false != nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, T, F, F, F, ...]
i = 10, a[i] == false != nil
0 1 2 3 4 5 6 7 8 9 10
a -> [F, F, T, T, F, T, F, T, F, F, F, ...]
------------------------------------------------------------------------------------------
n = 100 # 100,1000,10000,10000 と変更してみる
a = [false, false] # 0,1 は素数ではない(合成数である)
for i in 2 .. n do # 2 から n まで順にチェックする
if a[i] == nil # a[i] が素数か合成数か未チェックである
a[i] = true # i は素数である、と a[i] に記録する
k = 2*i # ↑
while k <= n do # ↑
a[k] = false # 素数 i の倍数 k は合成数である、と a[k] に記録する
k += i # ↓
end # ↓
end
end
counter = 0
for i in 0 .. n do # i を 0 から n まで動かしたとき
if a[i] # もし a[i] が true である(つまり i が素数である)
counter += 1 # ならば counter を1増やす
end
end
puts counter # 0 から n までの間に存在する素数の数
問15(発展課題): 問13,14 のプログラムをより効率的にしてみましょう。
例:
問16: 配列を利用して問4の fib1 を効率化してみましょう。
ヒント: fib1 では同じ計算を何度も繰り返しています。
memory = [0,1] # 定義より fib4(0) = 0, fib4(1) = 1 である
def fib4(m, n) # 一度計算した値は配列 m に記憶しておいて再利用する
if m[n] == nil # まだ fib4(n) が未計算であれば
m[n] = fib4(m, n-1) + fib4(m, n-2) # 計算して配列 m に記憶する
end
return m[n] # 計算済みの値を返す
end
for n in 0 .. 5 # 上限を 10, 15, 20, 25, 30 と大きくして
puts fib4(memory,n) # fib1 と計算時間を比較してみましょう
end
以前に触れておくべき項目でしたが、おそまきながら。以下で y は整数もしくは浮動小数点数です。
| y.abs | 絶対値 |
|---|---|
| y.ceil | 整数への丸め(天井) |
| y.floor | 整数への丸め(床) |
| y.round | 整数への丸め(四捨五入) |
| y.truncate | 整数への丸め(切り捨て) |
p = -3.14 puts p.abs puts p.ceil puts p.floor puts p.round puts p.truncate
puts (-3.14).abs puts (-3.14).ceil puts (-3.14).floor puts (-3.14).round puts (-3.14).truncate
def out(i)
printf("%f %f %f %f %f %f\n", i, i.abs, i.ceil, i.floor, i.round, i.truncate)
end
for n in [1.9, 1.1, -1.1, -1.9]
out(n)
end
問17: 浮動小数点数 x を入力したときにその abs, ceil, floor, round, truncate を表示するプログラムを考えてみましょう。
x = gets.to_f
printf("%f %f %f %f %f\n", x.abs, x.ceil, x.floor, x.round, x.truncate)
いくつかの数学的な関数と定数が定義済みです。詳細については オンラインマニュアル を参照してください。
| acos(x) | ラジアン単位での逆三角関数 |
|---|---|
| asin(x) | ラジアン単位での逆三角関数 |
| atan(x) | ラジアン単位での逆三角関数 |
| cos(x) | ラジアン単位での三角関数 |
| sin(x) | ラジアン単位での三角関数 |
| tan(x) | ラジアン単位での三角関数 |
| exp(x) | 指数関数 ex |
| log(x) | 自然対数 |
| log10(x) | 常用対数 |
| sqrt(x) | 平方根 √x |
| E | 自然対数の底 2.718281828... |
| PI | 円周率 3.1415926... |
include Math # 数学関数を利用するときの「おまじない」
printf("PI=%f, E=%f\n", PI, E)
x = PI/4
printf("x=%f, sin(x)=%f, cos(x)=%f, tan(x)=%f\n", x, sin(x), cos(x), tan(x))
x = 10
printf("x=%f, exp(x)=%f, log(x)=%f, log10(x)=%f, sqrt(x)=%f\n",
x, exp(x), log(x), log10(x), sqrt(x))
問18: 浮動小数点数 x を入力すると sin(x) + cos(x) を表示するプログラムを考えてみましょう。
include Math
x = gets.to_f
printf("%f\n", sin(x)+cos(x))
問19: 浮動小数点数 x を入力すると log(x) + exp(x) を表示するプログラムを考えてみましょう。 x が負値のときはどうなるでしょうか?
include Math
x = gets.to_f
printf("%f\n", log(x)+exp(x))
問20: 整数 n を入力すると tan(PI/n) を表示するプログラムを考えてみましょう。
include Math
n = gets.to_i
printf("%f\n", tan(PI/n))
問21: 整数 n を入力すると tan(PI/n) と atan(tan(PI/n) を表示するプログラムを考えてみましょう。
include Math
n = gets.to_i
z = PI/n
x = tan(z)
y = atan(x)
printf("%f %f %f %f\n", z, x, y, z-y)
整数 a, b に対して
a と b の最大公約数 = max { k | k は a を割り切る かつ k は b を割り切る }
a と b の最小公倍数 = min { k | a は k を割り切る かつ b は k を割り切る かつ k > 0 }
問22: 最大公約数を計算する関数 gcd(a,b) を定義してみましょう。
... # 必要に応じて補助関数を定義してもよい(以後とくに明記しない)
def gcd(a,b)
.... # ここを考える
return c # c は a,b の最大公約数
end
a = 1234567
b = 7654321
printf("gcd(%d,%d)=%d\n", a, b, gcd(a,b))
問23: 最小公倍数を計算する関数 lcm(a,b) を定義してみましょう。
def lcm(a,b)
.... # ここを考える
return c # c は a,b の最小公倍数
end
a = 1234567
b = 7654321
printf("lcm(%d,%d)=%d\n", a, b, lcm(a,b))
問24: 整数 a, b に対して m a + n b = gcd(a,b) となる m,n が必ず存在します。 この m,n を計算する関数 egcd を定義してみましょう。
def egcd(a,b)
... # ここを考える
return [m,n,c] # c は a,b の最小公倍数で a*m+b*n=c となっている
end
a = 1234567
b = 7654321
v = egcd(a,b)
printf("%d*%d+%d*%d=%d)=%d\n", a, v[0], b, v[1], v[2])