gal*_*gal 2 ruby optimization performance primes
这是一个素数筛子,但不是Eratosthenes的筛子.
我觉得它编写得很糟糕,因为我是编程和Ruby的新手.这只是我用Ruby编写的第二个程序,但我想尽可能优化它.问题是我没有完全理解我需要改变什么以使其更快,除了我知道程序路径/数据结构不理想 - 我只是没有一个概念可以工作到MAKE他们理想
一个理想的答案不一定会说"将X改为Y",但如果它指向了这种信息的良好资源方向,或者我可以从中获得有关效率的信息的方法,那将会更有帮助.程序的不同部分.
count = 0
x = 0
$results = Array.new []
inpt = []
class PrimeFun
def initialize(x, y)
array1 = (x..y).to_a
array1.each do |n|
if PrimeFun.primelogic(n%60, n) == 1
array1.delete_if { |p| p % n == 0}
$results << n
elsif n == 2 || n == 3 || n == 5
$results << n
end
end
end
def self.primelogic(r, n)
@prime = case r
when 1, 13, 17, 29, 37, 41, 49, 53
formulaone(n)
when 7, 19, 31, 43
formulatwo(n)
when 11, 23, 47, 59
formulathree(n)
else -1
end
end
def self.formulaone(n)
@x = 1
@y = -1
until 4*(@x**2) >= n
@y = -@y if Math.sqrt(n-(4*(@x**2))).floor - Math.sqrt(n-(4*(@x**2))) == 0
@x += 1
end
@y
end
def self.formulatwo(n)
@x = 1
@y = -1
until 3*(@x**2) >= n
@y = -@y if Math.sqrt(n-(3*(@x**2))).floor - Math.sqrt(n-(3*(@x**2))) == 0
@x += 1
end
@y
end
def self.formulathree(n)
@x = 1
@y = -1
until 3*(@x**2) >= n
@y = -@y if Math.sqrt(((@x**2)+n)/3).floor - Math.sqrt(((@x**2)+n)/3) == 0 && @x > @y
@x += 1
end
@y
end
end
x = STDIN.gets.to_i
while count < x
inpt << STDIN.gets.chomp
count += 1
end
inpt.each do |n|
a = n.split(" ").map { |a| a.to_i }
PrimeFun.new(a[0], a[1])
$results << ""
end
puts $results
Run Code Online (Sandbox Code Playgroud)
您应该熟悉Ruby标准库中包含的Benchmark模块,以测量您的方法(不同版本)的运行时间.我没有通过Benchmark自己运行以下代码建议,它们只是一些关于如何提高代码速度和可读性的快速想法 - 随意对它们进行基准测试并报告结果!:-)
分析代码以找到瓶颈也是一个好主意 - 没有必要花费数小时优化代码的部分内容,而这些部分对总运行时间的影响不大.查看ruby-prof gem是一个很好的工具来帮助你解决这个问题.
现在快速浏览一下您的代码和一些改进建议.
如果不考虑您使用的实际算法,您的第一个业务应该是消除代码重复多次重复计算相同值的倾向.
此外,您似乎正在使用实例变量(@x,@ y等),其中局部变量可以很好地完成工作.更不用说你使用的类方法只能在同一个类的实例方法中调用.您应该将它们转换为实例方法.(这些不是真正的优化提示,而是关于如何改进Ruby代码的建议.)
以此方法为例:
def self.formulaone(n)
@x = 1
@y = -1
until 4*(@x**2) >= n
@y = -@y if Math.sqrt(n-(4*(@x**2))).floor - Math.sqrt(n-(4*(@x**2))) == 0
@x += 1
end
@y
end
Run Code Online (Sandbox Code Playgroud)
在循环中,你正在计算表达式4*(@x**2) 3倍.一个就足够了,所以将结果存储在临时局部变量fsq中.您还在循环内计算两次相同数字的平方根.再次,将值存储在临时变量根中,并使用它.
def formulaone_b(n)
x = 1
y = -1
until (fsq = 4*(x**2)) >= n
root = Math.sqrt(n - fsq)
y = -y if root.floor - root == 0
x += 1
end
y
end
Run Code Online (Sandbox Code Playgroud)
这应该是一个好的开始.
可能不是优化,但你可以通过事先计算x的范围来使代码更清晰,然后使用每个代码迭代它:
def formulaone_c(n)
y = -1
(1..Math.sqrt(n / 4)).each do |x|
root = Math.sqrt(n - 4*(x**2))
y = -y if root.floor == root # See below
end
y
end
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我也用root.floor - root == 0更简单但等价的比较替换了比较root.floor == root,删除了一个不必要的减法.
还有一个想法:不是计算n - 4*(x**2)每次迭代,而是通过注意x * 8 + 4每个步骤都会减少这个值来获得一点点速度,所以使用辅助变量d来更新前一个表达式的值,如下所示:
def formulaone_d(n)
y = -1
d = n - 4 # Value of n - 4*(x**2) when x = 1
(1..Math.sqrt(n / 4)).each do |x|
root = Math.sqrt(d)
y = -y if root.floor == root
d -= x * 8 + 4 # Value of n - 4*(x**2) after x increases
end
y
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
873 次 |
| 最近记录: |