2017年11月15日水曜日

Project Euler 第7問

Q.
素数を小さい方から6つ並べると 2, 3, 5, 7, 11, 13 であり, 6番目の素数は 13 である.
10 001 番目の素数を求めよ.

A.
これはもう素数のジェネレータを作って求めるしかない
(因みにrubyにはPrimeモジュールがあるが流石に使わない。)
さてどう書くか?
そのものズバリの関数がジェネレータとして定義されているがrequire 'generator'が気に入らない。

2) http://ryota-ka.hatenablog.com/entry/2015/04/23/010520 こちらでは

fib = Enumerator.new do |y|

のような形でフィボナッチ数列のジェネレータが書き始められている。yieldを直接使わず上記で参照されているパラメータのように見える変数 |y|がEnumerator::Yielderとして機能するようなので同記事の説明にあるように

y << 値 の式を用意してやればfibを呼び出すたびに継続してyを返してくれるようになる。
これを利用しようと思う。

具体的には 1)の中でフラッグを利用しているところは無くしたい。他はほぼ構想通りの定義なので初版では
そのままパクりたい。
次に 定義的に言うと「ある数がその数の平方根を超えない全ての素数で割り切れなければ素数である。」
のところを配列のフィルターとenumerableのメソッドで1行で書きたい。

問題は10001番めということなのでここもループを回さずにruby的に書きたい。
実はこれも 1)の中で説明されていて
prime().each_with_index do |n, i|
    break if n > 50
    puts "#{i + 1} 番目の素数は #{n} です"
end
とあるので丸パクリする。prime()のカッコは不要になるはずだけどね。

prime = Enumerator.new do |p|
p<<2
p<<3
primes = [2,3]
#次の素数の候補 n
n = 5
loop do
isprime = true
for i in 1...primes.size()
break if primes[i] * primes[i] > n
if n % primes[i] == 0
isprime = false
break
end
end
if isprime
p << n
primes.push(n)
end
n += 2
end
end

prime.each_with_index do |n, i|
break if i > 10001
puts "#{i + 1} 番目の素数は #{n} です" if i==10000
end

で、 104743 を得た。

注目したいのは primesという配列と isprimeってフラグ ここをなんとかしたい。

一応得た答えは下記だが100倍以上遅い。残念。
if primes.select{|i| i*i<=n}.any?{|j| n % j ==0}
else
p << n
primes.push(n)
end
n += 2

0 件のコメント:

dosvaxj3が更新されていた。

 最近、エミュレータ系をあまり触っていなかったのだけど久しぶりに見てみたらタイトルのようにdosvaxj3が更新されていた。 on emulatorでセルフにcなどのソースを書いて実行するのに母艦側の特定のフォルダをドライブとしてマウント出来たり普通に母艦のimeで漢字が入力でき...