我对Ruby比较陌生,但就语言而言似乎很简单。我正在使用Ruby进行Euler项目,我在以下方面遇到了很大的问题:
低于10的素数之和为2 + 3 + 5 + 7 = 17。 找出200万以下所有素数的总和。
我的代码:
beginning_time = Time.now
(1..10000).each { |i| i }
def isPrime(num)
factors = 0
primecount = 1
while primecount <= num
if (num%primecount == 0)
factors += 1
end
if (factors > 2)
return false
end
primecount += 1
end
return true
end
def make_sieve(num)
sieve = Array.new(num)
summation = 0
for i in 1..num
if(isPrime(i) == true)
summation += i
puts i
for x in i..num
if x%i == 0
# Go through entire array and make all multiples of i False
sieve[x] = false
else
sieve[i] = true
end
end
else
# If i is NOT prime, move to the next number. in the For Loop
next
end
end
puts summation
end
make_sieve(2000000)
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"
我认为我对筛子有正确的想法,但我真的不知道是什么让这个程序运行得如此之慢。我用20,000运行它需要大约15秒,这看起来仍然很慢,尽管输出速度比我输入2,000,000时快得多。
我在逻辑上或语法上或两者上都是错误的吗?
答案 0 :(得分:2)
你的isPrime()
测试在素数上非常慢;但你甚至不需要它。筛选的关键是,最初所有数字都标记为素数;然后对于每个素数,我们标记它的所有倍数。因此,当我们在筛子中找到某个条目时,我们已经知道它是否是素数 - 它是否标记为true
是否为素数,或者是否标记为false
为复合(a一些较小的素数的倍数。)
根本没有必要对它进行测试。
为了找到倍数,我们只计算:对于5,它是每个第5个条目之后; 7 - 每7。无需使用%
运算符对其进行测试,只需立即设置为false
即可。无需将其中任何一个设置为true
,因为所有数字在开始时都设置为true
。
答案 1 :(得分:2)
你似乎在Ruby中编写JavaScript代码,并且缺少使Ruby如此优雅的微妙之处。你应该看看像Ruby Best Practices这样的东西,这是一个很轻松的阅读,但处理使用Ruby习语而不是强加另一种语言的概念。
正如已经说过的,Eratosthenes筛子的重点在于你只需从列表中删除所有化合物编号,只留下素数。没有必要检查每个元素的完整性。
这是一个Rubyish解决方案。它运行大约1.5秒。由数组元素N
表示的数字N-1
稍微复杂一点,因此(i+i+1 .. num).step(i+1)
相当于(n * 2 .. num).step(n)
def make_sieve(num)
sieve = Array.new(num, true)
sieve.each_with_index do |is_prime, i|
next if i == 0 or not is_prime
(i+i+1 .. num).step(i+1) { |i| sieve[i] = false }
end
puts sieve.each_index.select { |i| sieve[i] }.map { |i| i+1 }.inject(:+)
end
make_sieve(2_000_000)
<强>输出强>
142913828923