哪个是查找素数的最快算法?

时间:2009-01-17 18:42:22

标签: c++ algorithm primes

使用C ++找出素数的最快算法是什么?我使用筛选算法,但我仍然希望它更快!

18 个答案:

答案 0 :(得分:73)

Sieve of Atkin的快速实施是Dan Bernstein的primegen。这个筛子比Sieve of Eratosthenes更有效。他的页面有一些基准信息。

答案 1 :(得分:27)

如果它必须非常快,你可以包括一个素数列表:
http://www.bigprimes.net/archive/prime/

如果您只需知道某个数字是否为素数,则会有prime tests listed on wikipedia种{}。它们可能是确定大数是否为素数的最快方法,特别是因为它们可以告诉您数字是否不是是素数。

答案 2 :(得分:25)

他,我知道我是一个问题死灵法师回答旧问题,但我刚刚在网上找到了这个问题,以寻求实现有效素数测试的方法。

到目前为止,我认为最快的素数测试算法是Strong Probable Prime(SPRP)。我引用了Nvidia CUDA论坛:

  

数论中一个更实际的利基问题必须要做   识别素数。给定N,你怎么能有效率   确定它是否是素数?这不仅仅是一个问题   问题,它可能是代码中需要的真实问题,也许在您需要时   动态查找特定范围内的主要哈希表大小。如果是N.   是2 ^ 30的顺序,你真的想做30000   分裂测试搜索任何因素?显然不是。

     

这个问题的常见实际解决方案是一个简单的测试   欧拉可能的素数检验,以及更强大的推广   称为强可能素数(SPRP)。这是一个测试   整数N可以概率地将其归类为素数或者不是   重复测试可以增加正确性概率。缓慢的部分   测试本身主要涉及计算类似的值   A ^(N-1)模N.任何实现RSA公钥加密的人   变体使用了这种算法。它对于大整数都很有用   (如512位)以及普通的32或64位整数。

     

测试可以从概率拒绝变为   通过预先计算某些测试输入来确定原始性   已知的参数总是对N的范围成功。   不幸的是,这些“最着名的测试”的发现是有效的   搜索一个巨大的(实际上是无限的)域名。 1980年,第一个名单   有用的测试是由Carl Pomerance创造的(以其为名而闻名)   使用Quadratic Seive算法对RSA-129进行因子分析。)后来的Jaeschke   1993年显着改善了结果。2004年,张和唐   改进了搜索领域的理论和局限。 Greathouse和   利文斯通发布了迄今为止最现代的结果   网站,http://math.crg4.com/primes.html,一个巨大的最佳结果   搜索域。

有关详细信息,请参阅此处: http://primes.utm.edu/prove/prove2_3.htmlhttp://forums.nvidia.com/index.php?showtopic=70483

如果您只是需要一种方法来生成非常大的素数而不关心生成所有素数<整数n,您可以使用Lucas-Lehmer测试来验证Mersenne素数。梅森素数以2 ^ p -1的形式存在。我认为Lucas-Lehmer测试是发现梅森素数的最快算法。

如果您不仅想要使用最快的算法而且还想使用速度最快的硬件,请尝试使用Nvidia CUDA实现它,为CUDA编写内核并在GPU上运行。

如果你发现足够多的素数,你甚至可以赚到一些钱,EFF正在奖金从$ 50K到$ 250K: https://www.eff.org/awards/coop

答案 3 :(得分:16)

有100%的数学测试可以检查数字P是素数还是复合数,称为AKS Primality Test

概念很简单:给定一个数字P,如果(x-1)^P - (x^P-1)的所有系数都可被P整除,则P是素数,否则它是综合数字。

例如,给定P = 3,将给出多项式:

   (x-1)^3 - (x^3 - 1)
 = x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
 = 3x^2 - 3x

系数可以被3整除,因此数字是素数。

例如P = 4,这不是素数会产生:

   (x-1)^4 - (x^4-1)
 = x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
 = -4x^3 + 6x^2 - 4x

在这里,我们可以看到系数6不能被4整除,因此它不是素数。

多项式(x-1)^PP+1个术语,可以使用组合找到。因此,此测试将在O(n)运行时运行,因此我不知道这有多大用处,因为您可以简单地将i从0重复到p并测试剩余。

答案 4 :(得分:5)

您的问题是决定特定号码是否为素数?然后你需要一个素性测试(简单)。或者你需要所有素数达到给定数量?在那种情况下,素筛是好的(容易,但需要记忆)。或者你需要一个数字的素因子?这需要分解(如果你真的想要最有效的方法,那么很难对大数字进行分解)。你看的数字有多大? 16位? 32位?更大?

一种巧妙而有效的方法是预先计算素数表并使用位级编码将它们保存在文件中。该文件被认为是一个长位向量,而位n表示整数n。如果n为素数,则其位设置为1,否则为零。查找非常快(您计算字节偏移和位掩码)并且不需要将文件加载到内存中。

答案 5 :(得分:3)

Rabin-Miller是标准的概率素性测试。 (你运行它K次,输入数字肯定是复合的,或者它可能是错误的概率4 -K 。(几百次迭代,它几乎肯定告诉你真相)< / p>

存在非概率(确定性)variant of Rabin Miller

Great Internet Mersenne Prime Search(GIMPS)已经找到了世界上最大的已证明素数的记录(截至2017年6月,2 74,207,281 - 1),使用several algorithms,但这些是特殊形式的素数。然而,上面的GIMPS页面确实包括一些一般的确定性素性测试。它们似乎表明哪种算法“最快”取决于要测试的数量的大小。如果您的数字符合64位,那么您可能不应该使用一种方法来处理数百万位数的素数。

答案 6 :(得分:2)

这取决于您的申请。有一些注意事项:

  • 您是否只需要一些数字是素数的信息,您是否需要所有素数达到一定限度,或者您是否需要(可能)所有素数?
  • 你需要处理的数字有多大?

米勒 - 拉宾和模拟测试只比一定数量的筛子更快(我相信大约几百万左右)。在此之下,使用试验部门(如果您只有几个数字)或筛子更快。

答案 7 :(得分:1)

我会让你决定是否最快。

using System;
namespace PrimeNumbers
{

public static class Program
{
    static int primesCount = 0;


    public static void Main()
    {
        DateTime startingTime = DateTime.Now;

        RangePrime(1,1000000);   

        DateTime endingTime = DateTime.Now;

        TimeSpan span = endingTime - startingTime;

        Console.WriteLine("span = {0}", span.TotalSeconds);

    }


    public static void RangePrime(int start, int end)
    {
        for (int i = start; i != end+1; i++)
        {
            bool isPrime = IsPrime(i);
            if(isPrime)
            {
                primesCount++;
                Console.WriteLine("number = {0}", i);
            }
        }
        Console.WriteLine("primes count = {0}",primesCount);
    }



    public static bool IsPrime(int ToCheck)
    {

        if (ToCheck == 2) return true;
        if (ToCheck < 2) return false;


        if (IsOdd(ToCheck))
        {
            for (int i = 3; i <= (ToCheck / 3); i += 2)
            {
                if (ToCheck % i == 0) return false;
            }
            return true;
        }
        else return false; // even numbers(excluding 2) are composite
    }

    public static bool IsOdd(int ToCheck)
    {
        return ((ToCheck % 2 != 0) ? true : false);
    }
}
}

在配备2.40 GHz处理器的Core 2 Duo笔记本电脑上,查找并打印1至1,000,000范围内的质数大约需要大约82秒。它找到了 78,498 个质数。

答案 8 :(得分:0)

我最近写了这段代码来求数字的总和。可以很容易地修改它以查找一个数字是否为素数。基准测试位于代码之上。

// built on core-i2 e8400
// Benchmark from PowerShell
// Measure-Command { ExeName.exe }
// Days              : 0
// Hours             : 0
// Minutes           : 0
// Seconds           : 23
// Milliseconds      : 516
// Ticks             : 235162598
// TotalDays         : 0.00027217893287037
// TotalHours        : 0.00653229438888889
// TotalMinutes      : 0.391937663333333
// TotalSeconds      : 23.5162598
// TotalMilliseconds : 23516.2598
// built with latest MSVC
// cl /EHsc /std:c++latest main.cpp /O2 /fp:fast /Qpar

#include <cmath>
#include <iostream>
#include <vector>

inline auto prime = [](std::uint64_t I, std::vector<std::uint64_t> &cache) -> std::uint64_t {
    std::uint64_t root{static_cast<std::uint64_t>(std::sqrtl(I))};
    for (std::size_t i{}; cache[i] <= root; ++i)
        if (I % cache[i] == 0)
            return 0;

    cache.push_back(I);
    return I;
};

inline auto prime_sum = [](std::uint64_t S) -> std::uint64_t {
    std::uint64_t R{5};
    std::vector<std::uint64_t> cache;
    cache.reserve(S / 16);
    cache.push_back(3);

    for (std::uint64_t I{5}; I <= S; I += 8)
    {
        std::uint64_t U{I % 3};
        if (U != 0)
            R += prime(I, cache);
        if (U != 1)
            R += prime(I + 2, cache);
        if (U != 2)
            R += prime(I + 4, cache);
        R += prime(I + 6, cache);
    }
    return R;
};

int main()
{
    std::cout << prime_sum(63210123);
}

答案 9 :(得分:0)

kubectl exec -it alertmanager-0 cat /etc/alertmanager/alertmanager.yml

global: {}
receivers:
- name: default-receiver
route:
  group_interval: 5m
  group_wait: 10s
  receiver: default-receiver
  repeat_interval: 3h
templates:
- /etc/alertmanager/*.tmpl

这可以无限地列出素数。抱歉,我在刚开始编程 3 天时就编写了这个程序,因此它使用了非常基本的功能。 在评论部分建议的编辑之后,它会在 13 秒内打印出高达 1,000,000 的素数。

答案 10 :(得分:0)

我今天用C编写,与tcc一起编写,是几年前在准备竞争性考试时发现的。不知道有没有人写过它。它确实非常快(但是您应该决定是否很快)。花一两分钟在i7处理器上发现大约1,00,004个质数在10到1,00,000,000之间,平均CPU使用率为32%。 如您所知,只有那些最后一位数字为1,3,7或9的素数 并检查该数字是否为质数,则必须将该数字除以先前找到的质数。 因此,首先取四个数字的组= {1,3,7,9}, 用已知质数除以测试 如果提示不是零,则数字为素数,将其添加到素数数组中。 然后将10添加到组中,使其变为{11,13,17,19}并重复该过程。

#include <stdio.h>
int main() {    
    int nums[4]={1,3,7,9};
    int primes[100000];
    primes[0]=2;
    primes[1]=3;
    primes[2]=5;
    primes[3]=7;
    int found = 4;
    int got = 1;
    int m=0;
    int upto = 1000000;
    for(int i=0;i<upto;i++){
        //printf("iteration number: %d\n",i);
        for(int j=0;j<4;j++){
            m = nums[j]+10;
            //printf("m = %d\n",m);
            nums[j] = m;
            got = 1;
            for(int k=0;k<found;k++){
                //printf("testing with %d\n",primes[k]);
                if(m%primes[k]==0){
                    got = 0;
                    //printf("%d failed for %d\n",m,primes[k]);
                    break;
                }
            }
            if(got==1){
                //printf("got new prime: %d\n",m);
                primes[found]= m;
                found++;
            }
        }
    }
    printf("found total %d prime numbers between 1 and %d",found,upto*10);
    return 0;
}

答案 11 :(得分:-1)

我总是使用这种方法计算筛选算法后的素数。

void primelist()
 {
   for(int i = 4; i < pr; i += 2) mark[ i ] = false;
   for(int i = 3; i < pr; i += 2) mark[ i ] = true; mark[ 2 ] = true;
   for(int i = 3, sq = sqrt( pr ); i < sq; i += 2)
       if(mark[ i ])
          for(int j = i << 1; j < pr; j += i) mark[ j ] = false;
  prime[ 0 ] = 2; ind = 1;
  for(int i = 3; i < pr; i += 2)
    if(mark[ i ]) ind++; printf("%d\n", ind);
 }

答案 12 :(得分:-1)

我不知道任何预定义算法,但是我创建了自己的算法,速度非常快。它可以在不到1秒的时间内处理20位数字。该程序的最大容量为18446744073709551615。程序为:

#include <iostream>
#include <cmath>
#include <stdlib.h>

using namespace std;

unsigned long long int num = 0;

bool prime(){
if(num % 2 == 0 || num == 1){
    return false;
}

unsigned long int square_root = sqrt(num);
for(unsigned long int i = 3;i <= square_root;i += 2){
    if(num % i == 0){
        return false;
    }
}

return true;
}

int main()
{
do{
    system("cls");
cout << "Enter number : ";
cin >> num;

if(prime()){
    cout<<"The number is a prime number"<<endl<<endl<<endl<<endl;
}else{
    cout<<"The number is not a prime number"<<endl<<endl<<endl<<endl;
}
system("pause");
}while(1);

return 0;
}

答案 13 :(得分:-1)

你可以试试这个代码,用更少的循环来获得素数的最快方法,比如 1000 这样的数字将得到少于 15 个循环

def divisors(integer):
    result = []
    i = 2
    j = integer/2
    while(i <= j):
        if integer % i == 0:
            result.append(i)
            if i != integer//i:
                result.append(integer//i)
        i += 1
        j = integer//i
    if len(result) > 0:
        return sorted(result)
    else:
        return f"{integer} is prime"


print(divisors(1827))
print(divisors(1025))
print(divisors(27))

答案 14 :(得分:-3)

#include<stdio.h>
main()
{
    long long unsigned x,y,b,z,e,r,c;
    scanf("%llu",&x);
    if(x<2)return 0;
    scanf("%llu",&y);
    if(y<x)return 0;
    if(x==2)printf("|2");
    if(x%2==0)x+=1;
    if(y%2==0)y-=1;
    for(b=x;b<=y;b+=2)
    {
        z=b;e=0;
        for(c=2;c*c<=z;c++)
        {
            if(z%c==0)e++;
            if(e>0)z=3;
        }
        if(e==0)
        {
            printf("|%llu",z);
            r+=1;
        }
    }
    printf("|\n%llu outputs...\n",r);
    scanf("%llu",&r);
}    

答案 15 :(得分:-4)

我知道它稍晚一点,但这对于从搜索到达这里的人来说非常有用。无论如何,这里有一些JavaScript依赖于只需要测试素因子的事实,因此代码生成的早期素数被重新用作后者的测试因子。当然,首先过滤掉所有even和mod 5值。结果将在数组P中,并且该代码可以在i7 PC上在1.5秒内处理1000万个素数(或者约20个中的1亿个)。用C重写它应该非常快。

var P = [1, 2], j, k, l = 3

for (k = 3 ; k < 10000000 ; k += 2)
{
  loop: if (++l < 5)
  {
    for (j = 2 ; P[j] <= Math.sqrt(k) ; ++j)
      if (k % P[j] == 0) break loop

    P[P.length] = k
  }
  else l = 0
}

答案 16 :(得分:-4)

#include <iostream>

using namespace std;

int set [1000000];

int main (){

    for (int i=0; i<1000000; i++){
        set [i] = 0;
    }
    int set_size= 1000;
    set [set_size];
    set [0] = 2;
    set [1] = 3;
    int Ps = 0;
    int last = 2;

    cout << 2 << " " << 3 << " ";

    for (int n=1; n<10000; n++){
        int t = 0;
        Ps = (n%2)+1+(3*n);
        for (int i=0; i==i; i++){
            if (set [i] == 0) break;
            if (Ps%set[i]==0){
                t=1;
                break;
            }
        }
        if (t==0){
            cout << Ps << " ";
            set [last] = Ps;
            last++;
        }
    }
    //cout << last << endl;


    cout << endl;

    system ("pause");
    return 0;
}

答案 17 :(得分:-12)

#include<iostream>
using namespace std;

void main()
{
    int num,i,j,prime;
    cout<<"Enter the upper limit :";
    cin>>num;

    cout<<"Prime numbers till "<<num<<" are :2, ";

    for(i=3;i<=num;i++)
    {
        prime=1;
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                prime=0;
                break;
            }
        }

        if(prime==1)
            cout<<i<<", ";

    }
}