第02回について

すいません、きちんとアンケート読んでいないので次回へ廻します。


プログラム

変数

a
x
y
abc
aLPHA

予約語

変数名や関数名(後述)に使えない文字列です。


BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true
begin    else     in       rescue   undef
break    elsif    module   retry    unless
case     end      next     return   until

定数

true .... 真を表す値
false ... 偽を表す値
nil ..... 初期化されていない(条件判断の際には偽と解釈されます)

代入

x = 1
y = 2
str = "Hello"

演算子

-a ......... 符号の逆転
a + b  ..... 加算
a - b  ..... 減算
a * b  ..... 乗算
a / b  ..... 除算 (整除)
a % b  ..... 剰余
a ** b ..... 冪乗

a && b ..... 論理積
a and b .... 論理積
a || b ..... 論理和
a or b ..... 論理和
!a ......... 論理否定
not a ...... 論理否定

a < b ...... 比較 (a は b より小さい)
a <= b ..... 比較 (a は b 以下)
a >= b ..... 比較 (a は b 以上)
a > b ...... 比較 (a は b より大きい)
a == b ..... 比較 (a と b が等しければ true 、異なれば false)  ※ "=" ではない!
a <=> b .... 比較 (a > b ならば 1 ,l a と b が等しければ 0 、a < b ならば -1)

a += b ..... 変数 a の値を a + b の値にする
a -= b ..... 変数 a の値を a - b の値にする
a *= b ..... 変数 a の値を a * b の値にする
a /= b ..... 変数 a の値を a / b の値にする
a %= b ..... 変数 a の値を a % b の値にする
a **= b .... 変数 a の値を a ** b の値にする

範囲指定演算子

a .. b      両端を含む範囲
a ... b     終端(b)を含まない範囲

x = 1
x = ((x + 1) * (x - 1))**2
true && false
true || false

コメント

'#' から行末までの文はすべて無視されます

制御構造

プログラムの実行の流れを制御します。

文 (逐次実行)

改行もしくは ';' で区切られた文(式)は順番に実行されます。

a = 1
b = 1; c = 4
print a, "=",
      b, "<", c, "\n"

if 文 (条件分岐)


if a1 then
   b1
elsif a2 then
   b2
else
   b3
end

もし a1 が真であれば b1 を実行、 そうでなければ、 もし a2 が真であれば b2 を実行、 そうでなければ、 b3 を実行します。

真とはなにか? falsenil は「偽」、それ以外のすべての値は「真」です。

n = gets.to_i   # 文字列を読み込んで整数を返します。
if n > 0 then   # n が正だったら
  puts n        # n を印字
else            # さもなければ
  puts -n       # -n を印字
end

注: unless, case 文については省略します(if 文で代替可能)。

while 文 (ループ)


while a
   b
end

条件部 a が真である限り、b を実行し続けます。

a = 5         # a に 5 を代入
while a > 0   # a が正である限り
  puts a**3   # aの3乗を計算して印字
  a -= 1      # a の値を 1 減らす
end           # ループの最初(while ...)に戻る

プログラムの書き方によっては止まらなくなります。

a = 5         # a に 5 を代入
while a > 0   # a が正である限り
  puts a**3   # aの3乗を計算して印字
  a += 1      # a の値を 1 増やす
end           # ループの最初(while ...)に戻る

こういうときは RDE のメニューで "Run" -> "Terminate Process" を選択すると 強制的に実行を止めてくれます。それでも駄目だったら RDE 自体を強制終了させます。

注: until 文については省略します(while 文で代替可能)。

for 文 (ループ)


for var in obj
  c
end

obj 内の各要素を順番に var へ代入し、 c を実行します。

for x in 0 .. 5
  puts x*x
end
for x in 0 ... 5
  puts x*x
end

break, next, redo (ループ脱出)

while / for ループ中では break, next, redo という命令が利用できます。

例: 1+2+...n > 1000 となる最小の n は? 1+2+...n = n(n+1)/2 ですから n = 45 が解です。

s = 0             # 1+2+...n を保存しておくための変数 s の初期化
n = 0             
while s <= 1000   # 1+2+...n が 1000 以下である限り
  n += 1          # n を 1 増やす
  s += n          # 1+2+...n を計算・保存
end
puts n            # n を印字
s = 0             # 1+2+...n を保存しておくための変数 s の初期化
n = 0
while true        # 無限ループ
  n += 1          # n を 1 増やす
  s += n          # 1+2+...n を計算・保存
  if s > 1000     # 1+2+...n が 1000 以上になったらループを終了
    break
  end
end
puts n            # n を印字

例: コラッツ-角谷の予想

任意の正数(初期値)に対して

という操作を繰り返すと必ず 1 になります。いまだに証明されていない(はずです)。

x = gets.to_i     # 入力
while x > 1       # x が 1 より大きい限りループ
  if x % 2 == 0   #
    x /= 2        # x が偶数(2の剰余が0)ならば x を 2 で割った値を x とする
  else            #
    x = 3*x+1     # さもなければ(x が奇数ならば) 3x+1 を x とする
  end             #
  puts x          # x を出力する
end

問1: 途中経過の代りに、ループ終了時にループをどれだけ回ったかを出力するようにしてみましょう。

x = gets.to_i     # 初期値の入力
count = 0         # ループの回数を記録しておく変数
while x > 1       # x が 1 より大きい限りループ
  if x % 2 == 0   #
    x /= 2        # x が偶数(2の剰余が0)ならば x を 2 で割った値を x とする
  else            #
    x = 3*x+1     # さもなければ(x が奇数ならば) 3x+1 を x とする
  end             #
  count += 1      # count を 1 増やす
end               #
puts count        #

問2: 1 から 100 まで動かしたときに、一番たくさんループを回る初期値を見付けましょう。

問3: 調べる範囲の上限を 100 ではなく 1000, 10000 とした場合は?

e = 100             # 調べる範囲の上限
n = 1               # 一番たくさんループを回った初期値を保存する変数
c = 0               # 一番たくさん回ったループの回数を保存する変数
for i in (1 .. e)
  x = i
  count = 0         # ループの回数を記録しておく変数
  while x > 1       # x が 1 より大きい限りループ
    if x % 2 == 0   
      x /= 2        # x が偶数(2の剰余が0)ならば x を 2 で割った値を x とする
    else            
      x = 3*x+1     # さもなければ(x が奇数ならば) 3x+1 を x とする
    end             
    count += 1      # count を 1 増やす
  end               
  if count > c      # いままでで一番たくさんループを回ったならば
    n = i           # そのときの初期値を保存
    c = count       # そのときのループ回数を保存
  end
end
puts n, c           # 結果を出力する

補足

次週 11/7 は小金井祭のため休講です。次回は 11/14(月) です。