如何加速素性检查?

时间:2015-12-10 20:29:03

标签: performance delphi primes pascal

我有一个函数FIsPrime,它接受​​int64并返回一个布尔值True或False,具体取决于给定的int64是否为素数。

function FIsPrime(P:int64):boolean;

  var
  I:int64;
  RSqrtP:Extended;

  begin
    I:= 3;
    RSqrtP := sqrt(P) + 1;

    while ((P mod I) <> 0) AND (I <= RSqrtP) AND ((P mod 2) <> 0) do
      I := I + 2;

    if I < RSqrtP then
      FIsPrime := False
    else
      FIsPrime := True;
  end;

然而,虽然这有效,但它很慢。检查从10 6 到5×10 6 的数字需要4秒。

我正在测试大约10 12 和10 15 的数字 - 整个代码选择一个随机数××10呢 12 得到一个大的随机数。

这个随机数通过FIsPrime函数运行并递增1,直到它是素数:

function FFirstPrimeAbove(P:int64):int64;

  var
    BIsPrime: boolean;

  begin
    if P mod 2 = 0 then
      inc(P);

    repeat
      BIsPrime := FIsPrime(P);
      P := P + 2;
    until (BIsPrime);

    FFirstPrimeAbove := P;
  end;

这可能需要一段时间 - 对于10 12 约为6秒,对于10 15 为7。

虽然14秒不多,但很烦人。有没有办法通过更有效的算法来缩短这段时间?

我对Pascal很新,但多年来一直在编程 - 所以任何更有效的算法都会有用。

我看了AKS Test但是有很多行话可以克服 - “多项式同余关系”,“多项式的推广”和“二项式系数”来选择一些。

有关如何在Delphi中实现某些内容的任何基本提示将不胜感激。

2 个答案:

答案 0 :(得分:4)

将RSqrtP更改为Int64很可能会提高性能。我没有对它进行测试,但我希望将浮点值与int64值进行比较并不是最快的。

TOP 100 PERCENT带出循环。

此外,如果您不介意为您的应用程序设置更长的初始化时间,您可以加载2到X之间的所有素数列表,并在进入I + 2例程之前从它们开始。你不需要尝试除以非素数,因为这已经由素数来处理(即任何可以除以4的东西将除以2,任何可以除以49的东西也会是7,等等)

我发布an article关于使用素数的优化作为一个例子。也许您会在那里看到更多可以帮助您的信息。

答案 1 :(得分:1)

我怀疑提高速度的最有效的简单方法是创建一个已知素数表。

可能有太多的素数存储所有适合64位整数的素数。但是你可以存储少于sqrt(high(int64))的所有素数。然后当你循环抛出可能的除数时,你只能检查质数。这应该提供非常显着的好处。

因此,该算法概括为:

  • 使用小于sqrt(high(int64))的所有素数填充数组。这应该是预先计算的。
  • 要测试值N是素数,首先找到它的根sqrt(N)
  • 然后尝试将素数除以测试值,直到达到大于sqrt(N)的素数。
  • 如果你走得那么远,N就是素数。否则,如果你找到一个素数除数,它就不是素数。