【问题标题】:calculating prime numbers (streams and lambdas)计算素数(流和 lambda)
【发布时间】:2019-02-18 00:03:03
【问题描述】:

我编写了以下代码来获取 2..n 中的所有素数

private static LongStream getPrimesStream(long number) {
    return LongStream.range(2, number + 1)
            .filter(PrimeStreamTest::isPrime);
}

private static boolean isPrime(final long number) {
    return number == 2 || (number % 2 != 0 && LongStream
            .range(2, (long) Math.ceil(Math.sqrt(number + 1)))
            .filter(n -> n % 2 != 0)
            .noneMatch(divisor -> number % divisor == 0)
    );
}

我通过检查 2..sqrt(n) 的范围并过滤掉偶数来优化它,但现在我想通过存储所有以前找到的素数来进一步优化它(我不关心内存),这样我就可以过滤掉可被这些素数整除的数字,而不仅仅是可被 2 整除的数字。 我知道有更好的解决方案,但这只是对 lambda 和流的练习。

【问题讨论】:

  • 我相信更好的优化是 (a) 从 noneMatch() 更改为 anyMatch() 并否定结果 (b) 您拥有的过滤操作实际上非常仅限于检查2..sqrt(input) 之间的范围可被 2 整除,并且不检查其他素数,如 3,5.... 而不是所有这些步骤,只要数字可被 2,3 整除,流就会返回,4,5,....
  • @Baski:您为什么认为从noneMatch() 更改为anyMatch() 并否定结果会优化任何东西?
  • 如果您想以内存为代价优化速度,请使用BitSet 实现 Eratosthenes 筛。但是,由于这是流中的练习,您可以在 isPrime 中使用 getPrimesStream 来获取要测试的主要因素:return number == 2 || getPrimesStream((long) ceil(sqrt(number))).noneMatch(divisor -> number % divisor == 0);
  • @Misha:在这种情况下,如果isPrime 测试01(或简单地<2)并在启动不必要的流操作之前拒绝它们,它可能有助于性能.
  • @Holger 感谢您发现错误信息。我猜我被困在了精神障碍上,没有完全阅读 API 文档。

标签: lambda java-8 java-stream


【解决方案1】:

但现在我想通过存储所有以前找到的素数来进一步优化它

因为这需要将这些值存储在流管道的中间,即作为中间操作,并且根据他们的文档,大多数流中间操作应该是无状态的,因此您在这里尝试使用错误的工具来完成这项工作。

可以通过提取流的Spliterator 来实现有状态操作,将其包装到自定义的流中并将其重新包装到新的流中,但在这种情况下,考虑到这基本上就是您的流管道所做的一切,这似乎不太合适.

由于您尝试运行有状态且可并行化的计算任务,您可能希望改为查看fork-join frameworkCompletableFuture。前者也用作并行流实现的一部分,而后者使组合计算及其结果更容易。

【讨论】:

    【解决方案2】:

    试试这个

    public static boolean isPrime(final long number) {
       return LongStream.range(2,(long) Math.ceil(Math.sqrt(number + 1))).noneMatch(x -> number % x == 0);
    }
    

    【讨论】:

    • 我可以知道为什么 number + 1 吗?
    • @JigarNaik 我可能错了。我这样做只是为了避免舍入错误。
    • 为什么不调用 noneMatch() 而不是 anyMatch() 和一个否定符号?
    • @JeanneBoyarsky 感谢您的发帖。我已经更新了我的示例
    【解决方案3】:
    // check if number return true when it divided by it self and one only
    IntPredicate isDivisible = index -> number % index == 0;
    // test the number 
    isDivisible.test(number);
    // check if numbers between 2 and the provided number is prime 
    return IntStream.range(2, number - 1).noneMatch(isDivisible);
    

    【讨论】:

      【解决方案4】:

      我有几乎相同的任务要解决,我创建了下一个完美运行的代码:

      public static int[] primes(int n) {
          return IntStream.rangeClosed(2, n)
              .filter(p -> BigInteger.valueOf(p).isProbablePrime(50)).toArray();
      }
      

      使用它,您可以通过将数字除以已建立的素数来进行过滤。

      【讨论】:

        猜你喜欢
        • 2020-04-26
        • 2020-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-20
        • 1970-01-01
        • 2014-04-28
        • 1970-01-01
        相关资源
        最近更新 更多