如何修改我的Akka流Prime筛以排除已知质数的模数检查?

时间:2016-04-03 04:25:47

标签: algorithm akka sieve-of-eratosthenes akka-stream

我使用akka流编写了一个筛子来查找Int任意来源的主要成员:

object Sieve extends App {

  implicit val system = ActorSystem()
  implicit val mat = ActorMaterializer(ActorMaterializerSettings(system))
  implicit val ctx = implicitly[ExecutionContext](system.dispatcher)

  val NaturalNumbers = Source.fromIterator(() => Iterator.from(2))

  val IsPrimeByEurithmethes: Flow[Int, Int, _] = Flow[Int].filter {
    case n: Int =>
      (2 to Math.floor(Math.sqrt(n)).toInt).par.forall(n % _ != 0)
  }

  NaturalNumbers.via(IsPrimeByEurithmethes).throttle(100000, 1 second, 100000, ThrottleMode.Shaping).to(Sink.foreach(println)).run()
}

好的,所以这看起来效果不错。但是,至少有一些潜在的关注领域:

  1. 使用par.forall运行模数检查,即它们完全隐藏在Flow filter内,但我可以看到如何{{1}有用从每个Map的{​​{1}}到另一个candidate n。也许。
  2. 我正在以不必要的方式检查太多候选人 - 无论是根据以前的结果检查Map我已经知道的不是素数,还是检查多余的n % _。事实上,即使我认为n是素数,也只需检查那时已知的素数就足够了。
  3. 第二点是我更直接的关注​​。

    我认为我可以很容易地证明存在一种更有效的方法 - 通过过滤掉每个新素数的n % _

    那么......

    n

    现在找到source并过滤来源后,我们需要知道下一个候选人是否为2, 3, 4, 5, 6, 7, 8, 9, 10, 11... => (after finding p=2) 2, 3, 5, 7, 9, , 11... => (after finding p=3) 2, 3, 5, 7, , 11... => ... 。好吧,如果最大的已知素数大于它的根,我们可以肯定地说它是素数,这将永远发生我相信,所以只需选择下一个元素就足够了......

    p

    在我看来,这就像重写最初提供的筛子一样,以引入严格的顺序依赖为代价进行更少的检查。

    另一个想法 - 我可以通过符号来解决约束,比如需要素数的最小模数检查等等。

    我是在叫错树吗?如果没有,我怎么能以这种方式搞乱我的来源?

1 个答案:

答案 0 :(得分:2)

我最近刚刚开始摆弄akka流,所以可能有比这更好的解决方案(特别是因为代码对我来说有点笨拙) - 但你的第二点似乎是我尝试构建的正确挑战akka流中的反馈循环。

在此处找到我的完整解决方案:https://gist.github.com/MartinHH/de62b3b081ccfee4ae7320298edd81ee

主要思想是积累已经找到的素数并将它们与输入的自然数流合并,这样可以根据N的结果完成素数检查:

def isPrime(n: Int, primesSoFar: SortedSet[Int]): Boolean =
  !primesSoFar.exists(n % _ == 0) &&
    !(primesSoFar.lastOption.getOrElse(2) to Math.floor(Math.sqrt(n)).toInt).par.exists(n % _ == 0)