Problem 7 - Project Eulerより

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10001st prime number?

最初の6つの素数2、3、5、7、11、および13を並べれば、6番目が13であることがわかる。

では10001番目の素数は何か。

Rubyで素因数を求めるで書いた next_primeメソッドとprime?メソッドをそのまま使おう

def nth_prime(nth)
   prime = 1
   n = 1
   until n > nth
     prime = next_prime(prime)
     n += 1
   end
   prime
 end
 def next_prime(prime)
   _next = prime + 1
   loop do
     return _next if prime?(_next)
     _next += 1
   end
 end
 def prime?(n)
   2.upto(n-1) do |i|
     return false if n.modulo(i).zero?
   end
   true
 end
 t = Time.now
 nth_prime 10001 # => 104743
 Time.now - t # => 263.424058

ちょっと時間が掛かる…

数字を小さくしてプロファイルを見る

ruby -r profile p7.rb 
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 63.80   172.72    172.72     1000   172.72   267.66  Integer#upto
 17.90   221.19     48.47  3711627     0.01     0.01  Fixnum#modulo
 17.42   268.34     47.15  3711627     0.01     0.01  Fixnum#zero?
  0.06   268.51      0.17     8918     0.02     0.02  Fixnum#+
  0.03   268.59      0.08     7918     0.01     0.01  Fixnum#-
  0.01   268.63      0.04     1000     0.04   267.71  Object#prime?
  0.00   268.63      0.00        2     0.00     0.00  IO#set_encoding
  0.00   268.63      0.00     1001     0.00     0.00  Fixnum#>
  0.00   268.63      0.00        2     0.00     0.00  Time#now
  0.00   268.63      0.00        2     0.00     0.00  Time#initialize
  0.00   268.63      0.00        3     0.00     0.00  Module#method_added
  0.00   268.63      0.00        1     0.00   580.00  Object#nth_prime
  0.00   268.63      0.00        1     0.00     0.00  Time#-
  0.00   270.74      0.00        1     0.00 270740.00  #toplevel

ボトルネックはやはりprime?メソッドだ…

素数の判定法に エラトステネスのふるいというのがある

エラトステネスの篩 - Wikipediaより

ステップ 1
 整数を最初の素数である 2 から昇順で探索リストに羅列する。
 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
ステップ 2
 リストの先頭の数を素数リストに記録する。
 素数リスト:2
 探索リスト:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
ステップ 3
 前のステップで素数リストに加えられた数の全ての倍数を、探索リストから削除する。
 素数リスト:2
 探索リスト:3 5 7 9 11 13 15 17 19
ステップ 4
 探索リストの最大値が素数リストの最大値の平方よりも小さい場合、素数リストおよび探索リストに残っている数が素数となる。探索リストの最大値が素数リストの最大値の平方よりも大きい場合、ステップ 2 に戻る。

これを利用して上のコードを少し改良してみる nth_primeメソッドにおいて 得られた素数をprime_listに持たせ prime?に渡すようにしよう

def nth_prime(nth)
   prime_list = [2]
   n = 2
   until n > nth
     prime_list << next_prime(prime_list)
     n += 1
   end
   prime_list.last
 end
 def next_prime(prime_list)
   _next = prime_list.last + 1
   loop do
     return _next if prime?(_next, prime_list)
     _next += 1
   end
 end
 def prime?(n, prime_list)
   prime_list.each { |i| return false if n != i and (n % i).zero? }
   return true if n < (prime_list.last ** 2)
   2.upto(n-1) do |i|
     return false if n.modulo(i).zero?
   end
   true
 end
 t = Time.now
 nth_prime 10001 # => 104743
 Time.now - t # => 21.216265

いくらかよくなったかな

Rubyでサムオブスクエアスクエアオブサム ~Rubyでオイラープロジェクトを解こう!Problem6

Problem 6 - Project Eulerより


The sum of the squares of the first ten natural numbers is, The square of the sum of the first ten natural numbers is, Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is \(3025 - 385 = 2640\). Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum. _ 最初の10個の自然数を二乗したものの合計は、 最初の10個の自然数の合計を二乗したものは、 よってこれらの差は、\(3025 - 385 = 2640\)である。 最初の100個の自然数を二乗したものの合計と、それら自然数の合計を二乗したものとの差を求めよ。 __

def sum_of_squares(limit)
   sum = 0
   1.upto(limit) do |n|
     sum += n ** 2
   end
   sum
 end
 def square_of_sum(limit)
   (1..limit).to_a.inject(:+) ** 2
 end
 limit = 100
 (sum_of_squares(limit) - square_of_sum(limit)).abs # => 25164150


blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS