检查Scala中的数字是否为O(sqrt(n))中的素数

Bar*_*ach 2 primes functional-programming scala for-comprehension

当检查nScala中是否是素数时,最常见的解决方案是简洁的单行,这几乎可以在SO上的所有类似问题中看到

  def isPrime1(n: Int) = (n > 1) && ((2 until n) forall (n % _ != 0))
Run Code Online (Sandbox Code Playgroud)

继续前进,重写它只是为了检查奇数

  def isPrime2(n: Int): Boolean = {
    if (n < 2) return false
    if (n == 2) return true
    if (n % 2 == 0) false
    else (3 until n by 2) forall (n % _ != 0)
  }
Run Code Online (Sandbox Code Playgroud)

但是,为了提高效率,我想将仅检查赔率与计算结果相结合sqrt(n),但不使用Math.sqrt.所以,因为i < sqrt(n) <==> i * i < n,我会编写类似C的循环:

def isPrime3(n: Int): Boolean = {
    if (n < 2) return false
    if (n == 2) return true
    if (n % 2 == 0) return false
    var i = 3
    while (i * i <= n) {
      if (n % i == 0) return false
      i += 2
    }
    true
  }
Run Code Online (Sandbox Code Playgroud)

问题是:

1)如何在第一个版本中实现最新版本的Scala功能样式?

2)我如何使用Scala for?我想到了类似于下面的东西,但不知道如何.

for {
    i <- 3 until n by 2
    if i * i <= n
  } { ??? }
Run Code Online (Sandbox Code Playgroud)

nma*_*mat 5

这是一种验证n是否为素数的方法,直到sqrt(n)不使用sqrt:

  def isPrime3(n: Int): Boolean = {
    if (n == 2) {
      true
    } else if (n < 2 || n % 2 == 0) {
      false
    } else {
      Stream.from(3, 2).takeWhile(i => i * i < n + 1).forall(i => n % i != 0)
    }
  }
Run Code Online (Sandbox Code Playgroud)

如果你想这样做直到n/2,这也是一种可能的优化(比这更糟sqrt(n)),你可以用以下代码替换最后一行:

 (3 to n/2 + 1 by 2).forall(i => n % i != 0)
Run Code Online (Sandbox Code Playgroud)

如果您愿意,还可以制作尾递归版本,这些内容如下:

  import scala.annotation.tailrec

  def isPrime3(n: Int): Boolean = {
    if (n == 2 || n == 3) {
      true
    } else if (n < 2 || n % 2 == 0) {
      false
    } else {
      isPrime3Rec(n, 3)
    }
  }

  @tailrec
  def isPrime3Rec(n:Int, i: Int): Boolean = {
    (n % i != 0) && ((i * i > n) || isPrime3Rec(n, i + 2))
  }
Run Code Online (Sandbox Code Playgroud)