次のような、繰り返しを使ったプログラムを作成せよ。
- a. 非負整数 n を受け取り、2^n を計算する。
- b. 非負整数 n を受け取り、n! = n × (n − 1) × · · · × 2 × 1 を計算する。
- c. 非負整数 n と r(≤ n) を受け取り、nCr を計算する。
$$ nCr = {n × (n - 1) × … × (n - r + 1) \over r × (r - 1) × … × 1} $$
前回はHTMLになって読めなかったので、お手数ですが #1 をご確認頂けますと幸いです。
前回作成した Sym classの +@ -@ !@ 関数を再定義することで、
階乗 (!Sym.new(4) => 24) などの機能追加を実施しました。
Sym は代数計算をするために各演算を再定義している class です。
今回作成した Sym class のコードについては最後に記載しました。
まず +@ -@ については、 +self.to_f, -self.to_f のみを返す関数を登録します。
つぎに!@ については、 self.to_i の階乗を計算して返す関数を登録します。
また前回同様に、 <=> 演算子から、値を代入するようになっています。
以上から、 a ~ c のコード は以下のようになります。
p2, n, r = (0..5).map do Sym.new end
p2 <=> +2
a = p2 ** n
b = !n
c = !n / !(n - r) / !r
puts " i \t| 2^n \t\t| n! \t\t| nC1 \t\t| nC2 \t\t| nC3 \t\t | nC4"
puts " :-\t| :- \t\t| :- \t\t| :-- \t\t| :-- \t\t| :-- \t\t | :-"
(0..9).map do |i|
n <=> i
puts " #{i} \t|" +
" 2^#{i} = #{a} \t|" +
" #{i}! = #{b} \t|" +
" #{i}C#{r <=> 1} = #{c} \t|" +
" #{i}C#{r <=> 2} = #{c} \t|" +
" #{i}C#{r <=> 3} = #{c} \t|" +
" #{i}C#{r <=> 4} = #{c}"
end
実行結果は以下のようになります。
| i | 2^n | n! | nC1 | nC2 | nC3 | nC4 |
|---|---|---|---|---|---|---|
| 0 | 2^0 = 1 | 0! = 1 | 0C1 = 1 | 0C2 = 0 | 0C3 = 0 | 0C4 = 0 |
| 1 | 2^1 = 2 | 1! = 1 | 1C1 = 1 | 1C2 = 0 | 1C3 = 0 | 1C4 = 0 |
| 2 | 2^2 = 4 | 2! = 2 | 2C1 = 2 | 2C2 = 1 | 2C3 = 0 | 2C4 = 0 |
| 3 | 2^3 = 8 | 3! = 6 | 3C1 = 3 | 3C2 = 3 | 3C3 = 1 | 3C4 = 0 |
| 4 | 2^4 = 16 | 4! = 24 | 4C1 = 4 | 4C2 = 6 | 4C3 = 4 | 4C4 = 1 |
| 5 | 2^5 = 32 | 5! = 120 | 5C1 = 5 | 5C2 = 10 | 5C3 = 10 | 5C4 = 5 |
| 6 | 2^6 = 64 | 6! = 720 | 6C1 = 6 | 6C2 = 15 | 6C3 = 20 | 6C4 = 15 |
| 7 | 2^7 = 128 | 7! = 5040 | 7C1 = 7 | 7C2 = 21 | 7C3 = 35 | 7C4 = 35 |
| 8 | 2^8 = 256 | 8! = 40320 | 8C1 = 8 | 8C2 = 28 | 8C3 = 56 | 8C4 = 70 |
| 9 | 2^9 = 512 | 9! = 362880 | 9C1 = 9 | 9C2 = 36 | 9C3 = 84 | 9C4 = 126 |
まず、前回とおなじく演算の左側のオペランドは Sym objectでないといけないので、
p2 <=> +2 という Sym object を定義することが必要でした。
つぎに、 階乗を計算する !@ 関数を(1..self.to_i).inject(:*) と再定義したのですが、
* は関数として定義しているため、 :* というように書くことができました。
また、数学では 0! = 1 と定義されているので、 self.to_i が0のときは 1をかえすよう、
|| 1 を最後に追加する必要がありました。
時間内に debug できなかったのですが、sum 関数を途中まで作成しました。
sum 内で値を動かす変数と、from=0 => to=∞ のような範囲を指定することで、各合計値を返します。
これらから、 _sin.sum(k, 0, n) のように sigma のような機能を追加する予定です。
_sin = m1 ** k / !(p2 * k + 1) * x ** (p2 * k + 1)
_cos = m1 ** k / !(p2 * k) * x ** (p2 * k)
sin = _sin.sum(k, 0, n)
cos = _cos.sum(k, 0, n)
sum 関数は以下のようになりました。
def sum(_, from, to) @_[->{
(from.to_i..to.to_i).inject(0) do |acc, i|
_ <=> i
acc + self.to_f
end
}] end
class Sym
def initialize(init = 0.0)
@v = init
@_ = ->fun{Sym.new(fun)}
end
def to_f() (@v.is_a? Numeric) ? @v: @v[] end
def to_i() self.to_f.to_i end
def to_s() self.to_f.to_s end
def +(_) @_[->{self.to_f + _.to_f}] end
def -(_) @_[->{self.to_f - _.to_f}] end
def *(_) @_[->{self.to_f * _.to_f}] end
def /(_) @_[->{self.to_f / _.to_f}] end
def %(_) @_[->{self.to_f % _.to_f}] end
def **(_) @_[->{self.to_f ** _.to_f}] end
def ==(_) self.to_f == _.to_f end
def <=>(_) @v = _ end
def +@() @_[->{+self.to_f}] end
def -@() @_[->{-self.to_f}] end
def !@() @_[->{(1..self.to_i).inject(:*) || 1}] end
end