加快“ProjectEuler 35:循环素数低于100万”的解决方案

时间:2013-12-16 19:41:53

标签: ruby performance

如果一个数字的所有旋转都是素数,则称为圆形素数。

例如,数字197有两个旋转:971和719.它们都是素数。

在100:2,3,5,7,11,13,17,31,37,71,73,79和97之下有十三个这样的素数。

N下方有多少个圆形素数?

1 <= N <= 1000000

require 'prime'
require 'benchmark'

def circular_prime_count(kk)
   primes = []
   count = 0
   Prime.each(kk) do |prime|
    pa= prime.to_s.split('')
    flag = true
    pa.count.times do |i|
      pa.rotate!
      flag = false if !Prime.prime?(pa.join.to_i)
    end 
    count+=1 if flag
   end
   count
end

[100, 200, 1000, 2000 ,10_000, 100_000, 1_000_000 ].each do |number|
  puts "Count of primes below #{number} is: #{circular_prime_count(number)}"
  Benchmark.bm do |x|
    x.report do 
      circular_prime_count(number)
    end
  end  
end

我对ruby 2.0.0p247的基准是:

100以下的素数是:13

       user     system      total        real
   0.000000   0.000000   0.000000 (  0.001891)

200以下的素数是:17

       user     system      total        real
   0.000000   0.000000   0.000000 (  0.004775)

1000以下的素数是:25

       user     system      total        real
   0.010000   0.000000   0.010000 (  0.005716)

2000以下的素数是:27

       user     system      total        real
   0.020000   0.000000   0.020000 (  0.018399)

10000以下的素数是:33

       user     system      total        real
   0.110000   0.000000   0.110000 (  0.105365)

100000以下的素数是:43

       user     system      total        real
   1.790000   0.000000   1.790000 (  1.789223)

低于1000000的素数是:55

       user     system      total        real
  43.870000   0.010000  43.880000 ( 43.971832)

你能帮助提高性能,在20秒内找到100万的数量吗?

我的笔记本型号是:HP Probook 4530s

处理器信息:

家庭:Core i5

制造商:英特尔(R)公司

ID:A7 06 02 00 FF FB EB BF

版本:Intel(R)Core(TM)i5-2450M CPU @ 2.50GHz

电压:1.2 V

外部时钟:100 MHz

最高速度:2500 MHz

当前速度:2500 MHz

状态:已填充,已启用

核心数:2

核心已启用:2

线程数:4

谢谢大家,所以最终的解决方案是:

require 'prime'
require 'benchmark'
require 'set'
def circular_prime_count_v2(search_max)
    max = if search_max == 10 ** (search_max.to_s.length - 1)
      search_max
    else
      10 ** search_max.to_s.length - 1 
    end
    primes = Prime.each(max).to_set
    count = 0
    primes.each do |prime|
      break if prime > search_max
      s = prime.to_s
      l = s.length
      l.times { |i| primes.include?(((s * 2)[i, l]).to_i) || break } || next
      count+=1
    end
    count
end
[100, 200, 1000, 2000 ,10_000, 100_000, 1_000_000 ].each do |number|
  puts "Count of primes below #{number} is: #{circular_prime_count_v2(number)}"
  Benchmark.bm do |x|
    x.report('circular_prime_count') do 
      circular_prime_count_v2(number)
    end
  end  
end

100以下的素数计数为:13

   user     system      total        real

circular_prime_count  0.000000   0.000000   0.000000 (  0.000482)

200以下的素数是:17

   user     system      total        real

circular_prime_count  0.000000   0.000000   0.000000 (  0.002683)

1000以下的素数计数为:25

   user     system      total        real

circular_prime_count  0.000000   0.000000   0.000000 (  0.003666)

2000年以下的素数计数是:27

   user     system      total        real

circular_prime_count  0.010000   0.000000   0.010000 (  0.005241)

10000以下的素数是:33

   user     system      total        real

circular_prime_count  0.000000   0.000000   0.000000 (  0.007074)

100000以下的素数计数为:43

   user     system      total        real

circular_prime_count  0.060000   0.000000   0.060000 (  0.057128)

1000000以下的素数计数为:55

   user     system      total        real

circular_prime_count  0.720000   0.000000   0.720000 (  0.727345)

1 个答案:

答案 0 :(得分:1)

更新

我创建了一个更快的实现。对于历史价值,它大致基于this post。从我的基本测试(有100万条记录),它比原来快40倍。

require 'prime'
require 'benchmark'
require 'set'

def circular_prime_count(kk)
  primes, count = [], 0
  Prime.each(kk) do |prime|
    pa= prime.to_s.split('')
    flag = true
    pa.count.times do |i|
      pa.rotate!
      flag = false if !Prime.prime?(pa.join.to_i)
    end 
    count+=1 if flag
  end
  count
end

def circular_prime_count_v2(search_max)
    primes = Prime.each(search_max).to_set
    count = 0
    primes.each do |prime|
      str = prime.to_s
      all_points_match = (0...str.length).collect { |i| primes.include?(((str * 2)[i, str.length]).to_i) || break }
      count+=1 if all_points_match
    end
    count
end

Benchmark.bm do |x|
  x.report('circular_prime_count') do 
    puts " Count: #{circular_prime_count(1000000)}"
  end

  x.report('circular_prime_count_v2') do
    puts " Count: #{circular_prime_count_v2(1000000)}"
  end
end

新结果

       user     system      total        real
circular_prime_count Count: 55
 39.430000   0.080000  39.510000 ( 39.603969)
circular_prime_count_v2 Count: 55
  0.900000   0.000000   0.900000 (  0.906725)