Last active
April 15, 2016 04:30
-
-
Save esehara/90c7bd8dcfb51d67a94c68f8df8aae64 to your computer and use it in GitHub Desktop.
wheel factorizationとか言うやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# M_kを、k番目までの素数の積を合計したものとする。 | |
# 例えばM2ならば2 * 3で6となる。これがホイールの | |
# 周期として定義される。 | |
# M2の場合、最初の素数以降、確率的に2, 4, 2, 4... | |
# の間隔で、素数の候補が表われる。これらは、自分の理解 | |
# するところによれば、2と3の倍数が表れない周期性を利用 | |
# している。 | |
M2_CYCLE_LENGTH = 6 | |
M2_CYCLE = [4, 2] | |
# 実際に生成されたリストを見ると | |
# | |
# 1, 5, | |
# 7, 11, | |
# 13, 17, | |
# 19, 23, | |
# 25, 29.. | |
# | |
# となるわけだが、25は素数ではない。 | |
# | |
# wheel factorizationのおそらくの弱点は、 | |
# 任意の倍数から除外される合成数を見逃すところにある。 | |
# 実際、25は2と3では割りきれない数である | |
# この解決方法は非常に簡単である。 | |
# それは、この周期を拡大すればよい。M3 = 2 * 3 * 5 = 30 | |
# に拡張する。 | |
M3_CYCLE_LENGTH = 30 | |
M3_PRIMES = [2, 3, 5] | |
M3_CYCLE = [6, 4, 2, 4, 2, 4, 6, 2] | |
# 当然、M3の場合にも合成数があり、49 = 7 * 7 が該当する。 | |
def wheel_factorization limit | |
wheel_numbers = [] | |
next_number = 11 | |
1.upto(limit) do |n| | |
wheel_numbers << next_number | |
next_number += M3_CYCLE[n % M3_CYCLE.size - 1] | |
break if limit < next_number | |
end | |
return M3_PRIMES + wheel_numbers - [1] | |
end | |
# --------------------------------------------- | |
# 以下 Helper | |
def not_prime? x, y | |
!(x == 1 || y == 1 || x == y) && (x % y == 0) | |
end | |
def print_not_prime numbers | |
numbers.each { |x| | |
numbers.each {|y| puts "#{x} = #{y} * #{x / y}" if not_prime? x, y} | |
} | |
end | |
LIMIT = 10000 | |
numbers = wheel_factorization LIMIT | |
# ------------------------------- | |
# 素数だけにする | |
# real 0m5.688s | |
# user 0m5.672s | |
# sys 0m0.012s | |
def prime_check! numbers | |
primes = [] | |
until numbers == [] | |
number = numbers[0] | |
numbers = numbers.select {|x| !(x % number == 0)}.to_a | |
primes << number | |
end | |
primes | |
end | |
primes = prime_check! numbers | |
#------------------------------- | |
# M3を手で求めるのはさすがにしんどい | |
def print_differences numbers | |
prev = 0 | |
diffs = [] | |
numbers.each do |x| | |
puts "#{x} = #{prev} + #{x - prev} " | |
diffs << (x - prev) | |
prev = x | |
end | |
diffs | |
end | |
# テスト用エラトステネスのふるい | |
def eratos limit | |
numbers = [*2..limit] | |
primes = [] | |
until numbers == [] | |
number = numbers[0] | |
numbers = numbers.select { |x| !(x % number == 0)}.to_a | |
primes << number | |
end | |
primes | |
end | |
p eratos(LIMIT) - primes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment