理解这个关于素数的Ruby程序

时间:2018-04-08 05:14:20

标签: ruby primes

这是一个来自教科书的程序:

# Initialize our counter
i = 1

# i: [0, 100]
while (i <= 100)          
  # Initialize prime flag 
  prime_flag = true
  j = 2
  # Test divisibility of i from [0, i/2]
  while (j <= i / 2)     
    # puts " i ==> " to i.to_s + " j ==> " + j.to_s 
    if (i % j == 0)       
     prime_flag = false
     # break
    end 
    j = j + 1
  end
    # We found a prime!
    if prime_flag
      puts "Prime ==> " + i.to_s
    end 
    # Increment the counter
    i += 1
end

while (j <= i / 2)引入了一个新循环。如果我们试图找到素数怎么办?这是为什么写的?素数不具有平方根。 j <= i / 2的目的是什么?我不明白为什么会引入j

1 个答案:

答案 0 :(得分:1)

你是对的,你应该只检查numbers <= floor(sqrt(i))。上述代码不必要地检查ceil(sqrt(i))i/2的数字。然而,它会给出正确的答案。

此外,这不是类似Ruby的代码。这太糟糕了,作者应该觉得很糟糕(除非他们打算向你展示一些不好的东西,以便当你看到如何更好地写出它时让你感到惊讶!)。

这里的代码是以类似Ruby的方式完成的。请注意,prime?绝对可以是一个单行,但我在问题的上下文中分解了更多行的可读性:

def prime?(i)                       # Define a function that takes 1 parameter `i`
  MAX_NUM_TO_CHECK = Math.sqrt(i)   # No need to check numbers greater than sqrt(i)
  (2..MAX_NUM_TO_CHECK).all? do |j| # Return `true` if the following line is true for
                                    # all numbers [2,MAX_NUM_TO_CHECK]
    i % j != 0                      # true if `i` is evenly not divisible by `j`. Any
                                    # input that evaluates to false here is not prime.
  end
end

# Test primality of numbers [1,100]
(1..100).each {|n| puts "Prime ==> #{n}" if prime? n}

我认为您的图书与此代码之间的最大区别是:

  • 算法的不同之处在于我们不检查所有值,而是将检查限制为<= sqrt(i)。一旦我们知道一个数字不是素数,我们也会停止检查。
  • 我们迭代Ranges而不是保留计数器。一旦获得语法,这个级别稍高一些并且更容易阅读。
  • 我将代码分成两部分,一个计算参数是否为素数的函数,然后迭代输入范围(1..100)。这对我来说似乎是一个很好的功能划分,有助于提高可读性。

此处使用的某些语言功能不在您的示例中:

  • 如果语句可以在表达式之后,则仅在谓词(if之后的事物)求值为true时才计算表达式。这可以使一些陈述更具可读性。
  • range写成(x..y),允许您快速描述一系列值,您可以在不保留计数器的情况下迭代这些值。
  • 内部代码

    do |param1, ..., paramN| <CODE>; end

    {|param1, ..., paramN| <CODE>}

    称为block。它是一个匿名函数(作为参数传递给另一个函数/方法的函数)。我们在all?each处使用此功能。

  • each用于在集合的每个元素上运行代码块,忽略返回值
  • all?可用于确定某个块是否为集合中的每个项目返回true

如果您不熟悉将代码传递给函数,这可能有点令人困惑。它允许您根据需要执行不同的代码。例如,each为集合中的每个项运行生成的块。您可以在该块中执行任何操作而不更改each的定义...您只需将其生成块并运行该块用适当的参数。 Here is a good blog post to get you started on how this works and what else you can use it for