逆数の和を算出する

 逆数の和を算出する問題を解いたので記録しておきます。ブログの仕様上インデントが整っていないのでそこはご了承ください。

 

1/1 = 1

1/1 + 1/2 = 1.5

1/1 + 1/2 + 1/3 = 1.8333...

 

 このような形で1からNまでの整数の逆数の和を出していき、その逆数の和が7を超える最小の値Nを出したいと思います。

 めちゃめちゃ非効率なやり方ではありますが、論理が飛躍しないように地道に複数のやり方を試してみました。

 

 以下の流れで話を進めていきます。

  1. 小数点を含める
  2. とりあえずN=20で試してみた
  3. 強引に答えを出してみた
  4. コードを美しくする

 

 

1. 小数点を含める

 まず具体的な数字で試してみると

num = 1/1 + 1/2 + 1/3 + 1/4
puts num

 実行結果は「1」となってしまいました。どうやら小数点がなくなってしまうみたいです。そこで「to_f」を使ってみると、実行結果は「2.08333...」となり、小数点も含まれるようになりました。

num = 1/1.to_f + 1/2.to_f + 1/3.to_f + 1/4.to_f
puts num

 ただこんなことをしなくても「1」を「1.0」に変えるだけでも小数点が含まれるようになりました。「整数÷整数=整数」という仕様になっているようなので小数点をつけてあげると良いみたいです。

num = 1.0/1 + 1.0/2 + 1.0/3 + 1.0/4
puts num

 

 

2. とりあえずN=20で試してみた

 先ほどは1、2、3と自分で具体的な数字を書いて試しましたが、今度はその数字を「n」にして試してみました。|n|というブロック変数は0から始まるので(n + 1)にしています。

num = 0
20.times do |n|
num += 1.0/(n + 1)
puts num
end

 この実行結果はこのようになりました。

1.0
1.5
1.8333333333333333
2.083333333333333
2.283333333333333
2.4499999999999997
2.5928571428571425
2.7178571428571425
2.8289682539682537
2.9289682539682538
3.0198773448773446
3.103210678210678
3.180133755133755
3.251562326562327
3.3182289932289937
3.3807289932289937
3.439552522640758
3.4951080781963135
3.547739657143682
3.597739657143682

 N=20で逆数の和は「3.597...」ですし、足していく逆数はどんどん小さくなるため、逆数の和が7を超える最小の値はかなり大きい数字になりそうです。勘では当てられそうにありません。

 

3. 強引に答えを出してみた

 もちろんここから原始的に答えを導くことも可能だと言えます。とりあえず1万回繰り返し処理をしてみて、逆数の和が7を超えた時に繰り返し処理をストップさせてみました。また、何回目でストップしたかが分かるようにブロック変数の中身を「timesCount」にしてみました。ブロック変数は0から始まるため、+1をした上で回数を出力させています。

num = 0
10000.times do |timesCount|
n = timesCount + 1
num += 1.0/n
if num >= 7
puts num
puts n
return
end
end

 実行結果は以下のようになりました。N = 616の時に初めて逆数の和が7になるようです。答え自体は合っていると思います。

7.001274097134162
616

 

 

4. コードを美しくする

 答えを出すことだけが目的ならば上記までのやり方でも構わないと思います。しかしとりあえず1万回繰り返してみたというのは、不適切な「仕組み化」だと言えます。

 ということで10000.timesではなくwhileを使ったものを試すことにしてみました。

num = []
sum = 0
n = 0
while sum < 7
n += 1
a = 1.0/n
num << a
sum = num.sum
end
puts num.length

 これでどうでしょうか。先ほどと同じく「616」という値が算出されました。合計が7を超えるまで繰り返し処理を行うようにして、配列に値を追加しながら合計を出すようにしていきました。配列を使っているのでlengthメソッドでNの値を出すようにしています。

 

 

 

 いかがでしたでしょうか。理解力を深めるために、論理を飛躍させずに地道に答えを導いてみました。僕は勉強不足であるため、もっと適切なコードはあるはずです。こういうやり方が使えるということを教えていただけたら嬉しいです。