【问题标题】:I need a better algorithm for prime checking我需要一个更好的算法来进行质数检查
【发布时间】:2014-05-11 19:35:17
【问题描述】:

素数真的很奇怪......我出于无聊创造了这个简单的模式。我在网上没有看到任何相似之处。如您所见,根据您选择的比例,图片有缺失线,范围从 1 到 1000000

我打算从 1 - 25,000,000 甚至 1 - 10,000,000,000 的值开始

也许使用筛分技术会有所帮助,但我需要一个足够的 java 实现,我使用由 2 个 for 循环组成的经典素数检查器,它确实会占用时间。

编辑:这是我的代码示例

 boolean checkPrime(long a)
 {
 long count = 0L;
    for(long op = 1;op<=a;op++)  
            if(a%op==0)
                     count++;

  return count ==2;
 }

更新:我为我的代码找到了一个简单的优化措施

 boolean checkPrime(long a)
 {
 long count = 0L;
    for(long op = 1;op<=a;op++)  
            if(a%op==0)
                      {
                       count++;
                               if(count>2)break; //here it is
                      }

  return count ==2;
 }

代码运行速度似乎快了 10 倍

我最终选择创建并坚持下去。

package superprime;
public class SuperPrime {
    static java.util.List primes = new java.util.ArrayList<Long>();
    public static void main(String[] args) {
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        long start = System.currentTimeMillis();
       primes.add(2);
       boolean flag = true;
       long u =primes.size();long wow;double val;
    for(long e = 3L; e<10000000;e=e+2){
        flag = true;
        for( wow = 0;(wow< u)&&flag;wow++){
            if(e%(Long.parseLong(primes.get((int)wow)+""))==0)
           flag=false;

        }
        if(flag)primes.add(e);
        val = Double.parseDouble(primes.get((int)u)+"");
        if((val == Math.sqrt(e+1))||(val == Math.sqrt(e+2)))u++;
   // if(e%250000==0)System.out.println((System.currentTimeMillis()-start)/1000.0+" @ "+e);
    }long end =System.currentTimeMillis();
     System.out.println(""+(end-start)/1000.0);
     wow = 1;
for(Object h : primes)System.out.println(++wow+"\t"+(Long.parseLong((h)+"")));

    }

}

【问题讨论】:

  • 查看维基百科以获得更好的算法
  • 我不确定我在这里看到一个问题...
  • 我试图根据我对维基百科页面的解释来编译结果,但我失败了。我只是一名高中生。
  • 使用埃拉托色尼筛。由于此应用程序的明确下限是 O(N),因此它几乎是最优的(除了log log N 因素)
  • @RichardKennethNiescior 你提到你没有实现维基百科的一些算法。你为什么不选择其中一个并专门问一个关于你在那里的困难的问题。此外,请遵循 Niklas 的建议并使用 Erasthotenes 筛。在某个地方查一下。该算法相当容易理解。 Niklas 的评论是关于算法计算复杂度的数学分析(与执行时间有关)。另外,请尝试更清楚地了解您将来的实际要求=)。

标签: java algorithm optimization solution


【解决方案1】:

您提供的代码正在为每个 a 进行操作。 这是改进它的简单方法:

boolean checkPrime(long a)
 {
 long count = 0L;
 for(long op = 2;op*op<=a;op++)  
        if(a%op==0)
                 return false;

  return true;
 }

现在它只进行 sqrt(a) 操作并且总是给出正确的答案。为了获得更好的执行时间,随机算法如 Rabin-Milers 算法:http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test

我在 c++ 中包含了 Rabin-Milers 算法的实现。

#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std;

const int losowania=20;

long long pote(long long x,long long k,long long m)//this function is counting (x^k)mod m
{
if(k==1)
{
    return x%m;
}
if(k%2==0)
{
    long long a=pote(x,k/2,m);
    return ((__int128_t)((__int128_t)a*(__int128_t)a)%(__int128_t)m);
}
else
{
    long long a=pote(x,k-1,m);
    return ((__int128_t)((__int128_t)a*(__int128_t)x)%(__int128_t)m);
}
}

bool Rabin_Miler(long long p,long long x)
{

if(pote(x,p-1,p)!=1)
{
    return false;
}
long long wyk=(p-1);
while(wyk%2==0)
{
    wyk/=2;
}
long long teraz=pote(x,wyk,p);
if(teraz==1)
{
    return true;
}
while(teraz!=1&&teraz!=p-1)
{
    teraz=(__int128_t)((__int128_t) teraz*(__int128_t)teraz)%(__int128_t)p;
}
if(teraz==1)
{
    return false;
}
else
{
    return true;
}
}

bool is_prime(long long p)
{
srand(100);
    for(int i=0;i<losowania;i++)
    {
        if(!Rabin_Miler(p,(rand()%(p-1))+1))
        {
            return false;
            break;
        }
    }
return true;
}

【讨论】:

  • 无论您使用什么算法,对于数十亿个数字,Prime 测试仍然会太慢。筛子是去这里的路
【解决方案2】:

如果你想找到每个素数,那么你可以使用一个版本的erathmus' sieve来生成前1000个左右,然后只检查先验素数的列表,因为它们是基本定理唯一有意义的因素的代数。如果您想找到所有素数,这几乎肯定比使用通用数字域筛更快,后者旨在在您没有素数列表时尝试有效地分解大数。这是我为 Euler Project Number 7 写的东西。它有两个功能,一个使用 Erathmus 的筛子找到所有到 1000 的素数,然后它使用素数列表作为输入来顺序处理下一个数字通过素数列表的试除法是素数。

public class NthPrime {

/**
 * @param args
 */
public static void main(String[] args) 
{
    int N = 10001;
    long startTime = System.currentTimeMillis();
    ArrayList<BigInteger> firstPrimes = primes(1000);
    System.out.println("The "+N +"th Prime is: " + Nthprime(firstPrimes, N));
    long stopTime = System.currentTimeMillis();
    long elapsedTime = stopTime - startTime;
    System.out.println(firstPrimes.toString());
    System.out.println(elapsedTime);

}

public static BigInteger Nthprime(ArrayList<BigInteger> primes, int N)
{
    if(N < primes.size())
    {

        return primes.get(N-1);

    }



    BigInteger start = primes.get(primes.size()-1);
    boolean bool = true;
    BigInteger ZERO = new BigInteger("0");
    BigInteger ONE = new BigInteger("1");
    BigInteger j = new BigInteger("1");
    while(bool)
    {
        boolean hasfactor = false;
        for(int i=0; i<primes.size(); i++)
        {

            BigInteger Q = start.add(j);
            BigInteger remainder = Q.mod(primes.get(i));

            if(remainder.equals(ZERO))
            {
                hasfactor = true;
                break;
            }
        }

        if(!hasfactor)
        {
            primes.add(start.add(j));

        }

        if(primes.size() == N)
        {
            bool = false;
        }

        j = j.add(ONE);
    }

    return primes.get(primes.size()-1);

}


public static ArrayList<BigInteger> primes(int N)
{
    boolean[] primes = new boolean[N+1];


    for(int j = 0; j<N+1; j++)
    {
        primes[j] = true;
    }
    int i = 2;
    while(i < N+1)
    {
     if(primes[i])
        {
            int j = 2*i;
            while(j<N+1)
            {
                primes[j] = false;
                j = j+i;

            }
        }
     i++;
    }
    ArrayList<BigInteger> allprimes = new ArrayList<BigInteger>();
    for(i=2; i<N+1; i++)
    {
        if(primes[i])
        {
            allprimes.add(new BigInteger((new Integer(i)).toString()));
        }
    }

    return allprimes;


}

}

【讨论】:

  • PS:你也可以考虑只查找prime项目的primes列表......
  • 此外,erathmus 的筛子更快,因此在示例代码中您可以提高素数的值。它会在我的机器上不到 100 毫秒的时间内找到所有小于 1,000,000 的素数。它受 int 的最大大小限制,因为它取决于数组,所以不会超过 2^32-1。这对你来说可能不是问题。它的复杂度是 n*log(log(n)),所以它比线性差,但不是我的很多。
  • 筛选所有低于 10 亿的素数需要 10 秒。通过使用 long[] 作为位图并省略偶数,您可以达到 2.7e11,这可能需要几场演出,也可能需要几个小时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-05
  • 2014-07-12
  • 2016-05-14
  • 2017-10-24
  • 1970-01-01
  • 2021-12-12
  • 2016-06-09
相关资源
最近更新 更多