前10000个素数最有效的代码?

时间:2008-08-03 05:45:21

标签: performance algorithm primes

我想打印前10000个素数。 任何人都可以给我最有效的代码吗? 澄清:

  1. 如果您的代码对n> 10000而言效率低,则无关紧要。
  2. 代码的大小无关紧要。
  3. 您不能以任何方式对值进行硬编码。

29 个答案:

答案 0 :(得分:47)

The Sieve of Atkin可能就是你要找的,它的上限运行时间是O(N / log log N)。

如果你只运行数字1和1比6的倍数少,它可能会更快,因为3以上的所有素数都是1,远离6的倍数。 Resource for my statement

答案 1 :(得分:37)

我建议使用Sieve of EratosthenesSieve of Atkin.

筛子或Eratosthenes可能是找到素数列表的最直观的方法。基本上你:

  1. 记下一个数字列表,从2到你想要的任何限制,比方说1000。
  2. 取第一个未被划掉的数字(第一次迭代,这是2)并从列表中删除该数字的所有倍数。
  3. 重复步骤2,直至到达列表末尾。所有未被划掉的数字都是素数。
  4. 显然,为了使这个算法更快地运行,可以做很多优化,但这是基本的想法。

    阿特金的筛子采用了类似的方法,但不幸的是,我不太了解它给你解释。但我确实知道我链接的算法需要8秒才能找出古代奔腾II-350上的所有素数高达1000000000

    Eratosthenes筛选源代码:http://web.archive.org/web/20140705111241/http://primes.utm.edu/links/programs/sieves/Eratosthenes/C_source_code/

    阿特金筛选源代码:http://cr.yp.to/primegen.html

答案 2 :(得分:18)

这并不严格违反硬编码限制,但非常接近。为什么不以编程方式下载此列表并将其打印出来呢?

http://primes.utm.edu/lists/small/10000.txt

答案 3 :(得分:12)

GateKiller,如何在break循环中向if添加foreach呢?这会加速很多的事情,因为如果像6可以被2整除,你就不需要用3和5来检查。(如果我有足够的声誉,我会投票给你的解决方案: - )...)

ArrayList primeNumbers = new ArrayList();

for(int i = 2; primeNumbers.Count < 10000; i++) {
    bool divisible = false;

    foreach(int number in primeNumbers) {
        if(i % number == 0) {
            divisible = true;
            break;
        }
    }

    if(divisible == false) {
        primeNumbers.Add(i);
        Console.Write(i + " ");
    }
}

答案 4 :(得分:11)

在Haskell中,我们几乎可以逐字逐句地记下Eratosthenes筛子的数学定义,“素数是1以上的自然数,没有任何复合数,其中复合物是通过枚举每个素数的倍数来找到的“:

primes = 2 : minus [3..] (foldr (\p r -> p*p : union [p*p+p, p*p+2*p..] r)
                                [] primes)

primes !! 10000几乎是即时的。

参考文献:


以上代码很容易调整为仅在赔率 primes = 2 : 3 : minus [5,7..] (foldr (\p r -> p*p : union [p*p+2*p, p*p+4*p..] r) [] (tail primes)) 。通过折叠在树状结构中,时间复杂度得到了很大改善(大约只有 log 因子高于最佳值),空间复杂度为drastically improved multistage primes production,在

primes = 2 : _Y ( (3:) . sieve 5 . _U . map (\p -> [p*p, p*p+2*p..]) )
  where
    _Y g = g (_Y g)                        -- non-sharing fixpoint combinator
    _U ((x:xs):t) = x : (union xs . _U . pairs) t       -- ~= nub.sort.concat
    pairs    (xs:ys:t)  = union xs ys : pairs t
    sieve k s@(x:xs) | k < x      = k : sieve (k+2) s   -- ~= [k,k+2..]\\s,
                     | otherwise  =     sieve (k+2) xs  --   when s⊂[k,k+2..]

(在Haskell中,括号用于分组,函数调用仅通过并置表示, (:) 是列表的 cons 运算符, (.) 是一个功能合成运算符: (f . g) x = (\y -> f (g y)) x = f (g x) )。

答案 5 :(得分:10)

@Matt:log(log(10000))是〜2

来自维基百科文章(您引用的)Sieve of Atkin

  

这个筛子可计算出N的质数   使用O(N/log log N)操作   只有N 1/2 + o(1)位的内存。那是   比筛子好一点   使用O(N)的Eratosthenes   操作和O(N 1/2 (log log N)/ log   N)内存位(A.O.L. Atkin, D.J. Bernstein, 2004)。这些渐近   计算复杂性包括   简单的优化,例如轮子   分解,分裂   计算到较小的块。

给定O(N)(对于Eratosthenes)和O(N/log(log(N)))(对于Atkin)的渐近计算复杂度,我们不能说(对于小N=10_000)如果实现哪个算法会更快。< / p>

Achim Flammenkamp在The Sieve of Eratosthenes写道:

引用者:

@ NUM1

  

对于大约10 ^ 9的间隔,   当然对于那些&gt; 10 ^ 10,筛子   Eratosthenes的表现优于   阿特金斯和伯恩斯坦的筛子   使用不可约的二元二次方   形式。请参阅他们的论文了解背景   信息以及第5段   戈尔韦博士的博士学位论文。

因此,10_000 Eratosthenes的筛子可以比阿特金筛子更快。

要回答OP,代码为prime_sieve.c(由num1引用)

答案 6 :(得分:7)

使用GMP,可以写下以下内容:

#include <stdio.h>
#include <gmp.h>

int main() {
  mpz_t prime;
  mpz_init(prime);
  mpz_set_ui(prime, 1);
  int i;
  char* num = malloc(4000);
  for(i=0; i<10000; i++) {
    mpz_nextprime(prime, prime);
    printf("%s, ", mpz_get_str(NULL,10,prime));
  }
}

在我的2.33GHz Macbook Pro上,执行如下:

time ./a.out > /dev/null

real    0m0.033s
user    0m0.029s
sys    0m0.003s

在同一台笔记本电脑上计算1,000,000个素数:

time ./a.out > /dev/null

real    0m14.824s
user    0m14.606s
sys     0m0.086s

GMP针对此类事物进行了高度优化。除非您真的想通过编写自己的算法来理解算法,否则建议您在C下使用libGMP。

答案 7 :(得分:5)

根本没有效率,但您可以使用正则表达式来测试素数。

/^1?$|^(11+?)\1+$/

如果对于由 k 1”组成的字符串, k 不是素数(即是否该字符串由一个“1”或任意数量的“1”组成,可以表示为 n - 产品。

答案 8 :(得分:4)

我修改了CodeProject上的代码以创建以下内容:

ArrayList primeNumbers = new ArrayList();

for(int i = 2; primeNumbers.Count < 10000; i++) {
    bool divisible = false;

    foreach(int number in primeNumbers) {
        if(i % number == 0) {
            divisible = true;
        }
    }

    if(divisible == false) {
        primeNumbers.Add(i);
        Console.Write(i + " ");
    }
}

在我的ASP.NET服务器上测试它需要大约1分钟才能运行。

答案 9 :(得分:3)

Sieve of Eratosthenes是要走的路,因为它的简单性和速度。我在C中的实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

int main(void)
{
    unsigned int lim, i, j;

    printf("Find primes upto: ");
    scanf("%d", &lim);
    lim += 1;
    bool *primes = calloc(lim, sizeof(bool));

    unsigned int sqrtlim = sqrt(lim);
    for (i = 2; i <= sqrtlim; i++)
        if (!primes[i])
            for (j = i * i; j < lim; j += i)
                primes[j] = true;

    printf("\nListing prime numbers between 2 and %d:\n\n", lim - 1);
    for (i = 2; i < lim; i++)
        if (!primes[i])
            printf("%d\n", i);

    return 0;
}

查找质数的CPU时间(使用单核的奔腾双核E2140 1.6 GHz)

  对于lim = 100,000,000

~4s

答案 10 :(得分:3)

这是我几天前在PowerShell中写过的Eratosthenes的Sieve。它有一个参数,用于识别应返回的素数的数量。

#
# generate a list of primes up to a specific target using a sieve of eratosthenes
#
function getPrimes { #sieve of eratosthenes, http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
    param ($target,$count = 0)
    $sieveBound = [math]::ceiling(( $target - 1 ) / 2) #not storing evens so count is lower than $target
    $sieve = @($false) * $sieveBound
    $crossLimit = [math]::ceiling(( [math]::sqrt($target) - 1 ) / 2)
    for ($i = 1; $i -le $crossLimit; $i ++) {
        if ($sieve[$i] -eq $false) {
            $prime = 2 * $i + 1
            write-debug "Found: $prime"
            for ($x = 2 * $i * ( $i + 1 ); $x -lt $sieveBound; $x += 2 * $i + 1) {
                $sieve[$x] = $true
            }
        }
    }
    $primes = @(2)
    for ($i = 1; $i -le $sieveBound; $i ++) {
        if($count -gt 0 -and $primes.length -ge $count) {
            break;
        }
        if($sieve[$i] -eq $false) {
            $prime = 2 * $i + 1
            write-debug "Output: $prime"
            $primes += $prime
        }
    }
    return $primes
}

答案 11 :(得分:2)

在Python中

import gmpy
p=1
for i in range(10000):
    p=gmpy.next_prime(p)
    print p 

答案 12 :(得分:2)

GateKiller改编并跟进,这是我使用的最终版本。

    public IEnumerable<long> PrimeNumbers(long number)
    {
        List<long> primes = new List<long>();
        for (int i = 2; primes.Count < number; i++)
        {
            bool divisible = false;

            foreach (int num in primes)
            {
                if (i % num == 0)
                    divisible = true;

                if (num > Math.Sqrt(i))
                    break;
            }

            if (divisible == false)
                primes.Add(i);
        }
        return primes;
    }

它基本相同,但我添加了“在Sqrt上打破”的建议并更改了一些变量以使其更适合我。 (我正在研究Euler并需要第10001个素数)

答案 13 :(得分:2)

Sieve似乎是错误的答案。筛子为您提供最多数字 N ,而不是第一个N 素数。运行@Imran或@Andrew Szeto,你可以获得N的素数。

如果您继续尝试使用越来越大的数字筛,直到达到一定大小的结果集,并使用已经获得的数字缓存,筛网可能仍然可用,但我相信它仍然不会比解决方案更快喜欢@ Pat's。

答案 14 :(得分:1)

使用Sieve of Eratosthenes,与“已知范围”的素数算法相比,计算速度更快。

通过使用wiki(https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)中的伪代码,我可以在C#上找到解决方案。

/// Get non-negative prime numbers until n using Sieve of Eratosthenes.
public int[] GetPrimes(int n) {
    if (n <= 1) {
        return new int[] { };
    }

    var mark = new bool[n];
    for(var i = 2; i < n; i++) {
        mark[i] = true;
    }

    for (var i = 2; i < Math.Sqrt(n); i++) {
        if (mark[i]) {
            for (var j = (i * i); j < n; j += i) {
                mark[j] = false;
            }
        }
    }

    var primes = new List<int>();
    for(var i = 3; i < n; i++) {
        if (mark[i]) {
            primes.Add(i);
        }
    }

    return primes.ToArray();
}

GetPrimes(100000000)需要2s和330ms。

注意 :值可能因硬件规格而异。

答案 15 :(得分:1)

这是我的VB 2008代码,它在我的工作笔记本电脑上找到所有素数&lt; 10,000,000,1分27秒。它跳过偶数,只查找&lt;测试号码的sqrt。它只是为了找到从0到一个值的素数。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 
Button1.Click

    Dim TestNum As Integer
    Dim X As Integer
    Dim Z As Integer
    Dim TM As Single
    Dim TS As Single
    Dim TMS As Single
    Dim UnPrime As Boolean
    Dim Sentinal As Integer
    Button1.Text = "Thinking"
    Button1.Refresh()
    Sentinal = Val(SentinalTxt.Text)
    UnPrime = True
    Primes(0) = 2
    Primes(1) = 3
    Z = 1
    TM = TimeOfDay.Minute
    TS = TimeOfDay.Second
    TMS = TimeOfDay.Millisecond
    For TestNum = 5 To Sentinal Step 2
        Do While Primes(X) <> 0 And UnPrime And Primes(X) ^ 2 <= TestNum
            If Int(TestNum / Primes(X)) - (TestNum / Primes(X)) = 0 Then
                UnPrime = False
            End If
            X = X + 1

        Loop
        If UnPrime = True Then
            X = X + 1
            Z = Z + 1
            Primes(Z) = TestNum
        End If
        UnPrime = True
        X = 0
    Next
    Button1.Text = "Finished with " & Z
    TM = TimeOfDay.Minute - TM
    TS = TimeOfDay.Second - TS
    TMS = TimeOfDay.Millisecond - TMS
    ShowTime.Text = TM & ":" & TS & ":" & TMS
End Sub

答案 16 :(得分:1)

以下Mathcad代码在3分钟内计算了第一百万个素数。

请记住,这将使用所有数字的浮点双精度,并且基本上被解释。我希望语法清晰。

enter image description here

答案 17 :(得分:1)

这是一个使用SoE形式的C ++解决方案:

#include <iostream>
#include <deque>

typedef std::deque<int> mydeque;

void my_insert( mydeque & factors, int factor ) {
    int where = factor, count = factors.size();
    while( where < count && factors[where] ) where += factor;
    if( where >= count ) factors.resize( where + 1 );
    factors[ where ] = factor;
}

int main() {
    mydeque primes;
    mydeque factors;
    int a_prime = 3, a_square_prime = 9, maybe_prime = 3;
    int cnt = 2;
    factors.resize(3);
    std::cout << "2 3 ";

    while( cnt < 10000 ) {
        int factor = factors.front();
        maybe_prime += 2;
        if( factor ) {
            my_insert( factors, factor );
        } else if( maybe_prime < a_square_prime ) {
            std::cout << maybe_prime << " ";
            primes.push_back( maybe_prime );
            ++cnt;
        } else {
            my_insert( factors, a_prime );
            a_prime = primes.front();
            primes.pop_front();
            a_square_prime = a_prime * a_prime;
        }
        factors.pop_front();
    }

    std::cout << std::endl;
    return 0;
}

请注意,此版本的Sieve可以无限期地计算素数。

另请注意,STL deque需要O(1)时间来执行push_backpop_front,以及通过下标进行随机访问。

resize操作需要O(n)次,其中n是要添加的元素数。由于我们如何使用此功能,我们可以将其视为一个小常量。

whilemy_insert循环的正文执行O(log log n)次,其中n等于变量maybe_prime。这是因为while的条件表达式将为maybe_prime的每个素因子计算一次为真。见&#34; Divisor function&#34;在维基百科上。

乘以调用my_insert的次数表明,O(n log log n)时间列出n素数...这不足为奇,Sieve的时间复杂度Eratosthenes应该有。

但是,虽然此代码 有效,但它不是效率最高 ...我强烈建议使用专门的库来生成素数,例如为primesieve。任何真正高效,优化的解决方案都将占用比任何人想要输入Stackoverflow更多的代码。

答案 18 :(得分:0)

由于您只希望前10000个素数,所以我建议不要编码复杂的算法 以下

boolean isPrime(int n){
//even but is prime
    if(n==2)
        return true;
//even numbers filtered already 
    if(n==0 || n==1 || n%2==0)
        return false;

// loop for checking only odd factors
// i*i <= n  (same as i<=sqrt(n), avoiding floating point calculations)
    for(int i=3 ; i*i <=n ; i+=2){
    // if any odd factor divides n then its not a prime!
        if(n%i==0)
            return false;
    }
// its prime now
    return true;
}

现在通话是您需要的主要通话

for(int i=1 ; i<=1000 ; i++){
    if(isPrime(i)){
       //do something
    }
}

答案 19 :(得分:0)

这是我找到的代码 我的笔记本电脑上的第一个10,000质量数据,0.049655秒,6秒内首次1,000,000个素数,15秒内首次2,000,000个素数 一点解释。该方法使用2种技术来查找素数

  1. 首先,任何非素数都是素数的倍数的复合,所以这个代码通过将测试数除以较小的素数而不是任何数来进行测试,这对于4位数而言计算至少减少10倍并且更多的是为了更大的数字
  2. 其次除了除以素数之外,它只划分小于或等于被测数的根的素数进一步减少计算,这是有效的,因为任何大于数字根的数将具有对应的数字必须小于数字的根,但由于我们已经测试了所有小于根的数字,因此我们不需要打扰数字大于被测数字的根。
  3. 第一个10,000素数的样本输出
    https://drive.google.com/open?id=0B2QYXBiLI-lZMUpCNFhZeUphck0 https://drive.google.com/open?id=0B2QYXBiLI-lZbmRtTkZETnp6Ykk

    这是C语言的代码, 输入1然后输入10,000以打印出前10,000个素数 编辑:我忘了这里包含数学库,如果你在windows或visual studio上应该没问题,但在Linux上你必须使用-lm参数编译代码或者代码可能无法工作
    示例:gcc -Wall -o“%e”“%f”-lm

    #include <stdio.h>
    #include <math.h>
    #include <time.h>
    #include <limits.h>
    
    /* Finding prime numbers */
    int main()
    {   
        //pre-phase
        char d,w;
        int l,o;
        printf("  1. Find first n number of prime numbers or Find all prime numbers smaller than n ?\n"); // this question helps in setting the limits on m or n value i.e l or o 
        printf("     Enter 1 or 2 to get anwser of first or second question\n");
        // decision making
        do
        {
            printf("  -->");
            scanf("%c",&d);
            while ((w=getchar()) != '\n' && w != EOF);
            if ( d == '1')
            {
                printf("\n  2. Enter the target no. of primes you will like to find from 3 to 2,000,000 range\n  -->");
                scanf("%10d",&l);
                o=INT_MAX;
                printf("  Here we go!\n\n");
                break;
            }
            else if ( d == '2' )
            {
                printf("\n  2.Enter the limit under which to find prime numbers from 5 to 2,000,000 range\n  -->");
                scanf("%10d",&o);
                l=o/log(o)*1.25;
                printf("  Here we go!\n\n");
                break;
            }
            else printf("\n  Try again\n");
        }while ( d != '1' || d != '2' );
    
        clock_t start, end;
        double cpu_time_used;
        start = clock(); /* starting the clock for time keeping */
    
        // main program starts here
        int i,j,c,m,n; /* i ,j , c and m are all prime array 'p' variables and n is the number that is being tested */
        int s,x;
    
        int p[ l ]; /* p is the array for storing prime numbers and l sets the array size, l was initialized in pre-phase */
        p[1]=2;
        p[2]=3;
        p[3]=5;
        printf("%10dst:%10d\n%10dnd:%10d\n%10drd:%10d\n",1,p[1],2,p[2],3,p[3]); // first three prime are set
        for ( i=4;i<=l;++i ) /* this loop sets all the prime numbers greater than 5 in the p array to 0 */
            p[i]=0;
    
        n=6; /* prime number testing begins with number 6 but this can lowered if you wish but you must remember to update other variables too */
        s=sqrt(n); /* 's' does two things it stores the root value so that program does not have to calaculate it again and again and also it stores it in integer form instead of float*/
        x=2; /* 'x' is the biggest prime number that is smaller or equal to root of the number 'n' being tested */
    
        /* j ,x and c are related in this way, p[j] <= prime number x <= p[c] */
    
        // the main loop begins here
        for ( m=4,j=1,c=2; m<=l && n <= o;)
        /* this condition checks if all the first 'l' numbers of primes are found or n does not exceed the set limit o */
        {
                // this will divide n by prime number in p[j] and tries to rule out non-primes
                if ( n%p[j]==0 )
                {
                    /* these steps execute if the number n is found to be non-prime */
    
                    ++n; /* this increases n by 1 and therefore sets the next number 'n' to be tested */
                    s=sqrt(n); /* this calaulates and stores in 's' the new root of number 'n' */
                    if ( p[c] <= s && p[c] != x ) /* 'The Magic Setting' tests the next prime number candidate p[c] and if passed it updates the prime number x */
                    {
                        x=p[c];
                        ++c;
                    }
                    j=1;
                    /* these steps sets the next number n to be tested and finds the next prime number x if possible for the new number 'n' and also resets j to 1 for the new cycle */
                    continue; /* and this restarts the loop for the new cycle */
                }
                // confirmation test for the prime number candidate n
                else if ( n%p[j]!=0 && p[j]==x )
                {
                    /* these steps execute if the number is found to be prime */
                    p[m]=n;
                    printf("%10dth:%10d\n",m,p[m]);
                    ++n;
                    s = sqrt(n);
                    ++m;
                    j=1;
                    /* these steps stores and prints the new prime number and moves the 'm' counter up and also sets the next number n to be tested and also resets j to 1 for the new cycle */
                    continue; /* and this restarts the loop */
                    /* the next number which will be a even and non-prime will trigger the magic setting in the next cycle and therfore we do not have to add another magic setting here*/
                }
                ++j; /* increases p[j] to next prime number in the array for the next cycle testing of the number 'n' */
                // if the cycle reaches this point that means the number 'n' was neither divisible by p[j] nor was it a prime number
                // and therfore it will test the same number 'n' again in the next cycle with a bigger prime number
        }
        // the loops ends
        printf("  All done !!\n");
        end = clock();
        cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
        printf("  Time taken : %lf sec\n",cpu_time_used);
    }
    

答案 20 :(得分:0)

这是一个古老的问题,但这里有些人人都缺少的东西...

对于素数,这种小的试验除法不是 慢...在100以下只有25个素数。要测试的素数很少,又有这么小的素数,我们可以抽出一个整洁的把戏!

如果a与b互质,则gcd a b = 1。好玩的字。表示它不共享任何主要因素。因此,我们可以通过一个GCD调用以几个素数测试除数。多少?好吧,前15个素数的乘积小于2 ^ 64。并且下一个10的乘积也小于2 ^ 64。这就是我们需要的全部25个。但这值得吗?

让我们看看:

check x = null $ filter ((==0) . (x `mod`)) $ [<primes up to 101>]
Prelude> length $ filter check [101,103..85600]
>>> 9975
(0.30 secs, 125,865,152 bytes

a = 16294579238595022365 :: Word64
b = 14290787196698157718
pre = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) [99,101..85600]
main = print $ length primes

Prelude> main
>>> 10000
(0.05 secs, 36,387,520 bytes)

在那里改善了6倍。

({length将强制计算列表。默认情况下,Haskell一次打印1个Unicode字符,因此实际上 printing 列表将主导时间或主导列表。实际使用的代码量。)

当然,这是在旧笔记本电脑上以GHCi(运行解释代码的repl)运行的,它不会将这些数字中的任何一个解释为int64甚至是BigInt,也不会即使您要求它(嗯,您可以 强制使用它,但是它很丑陋,但实际上并没有帮助)。它会将每个单个数字解释为可以通过字典查找专用于某种特定类型的通用 Integer-like 事物,并且它遍历一个链表(此处未合并,因为未编译) ) 3次。有趣的是,手动融合两个过滤器实际上会使REPL的速度放慢。

让我们编译它:

...\Haskell\8.6\Testbed>Primes.exe +RTS -s
10000
606,280 bytes allocated in the heap
Total   time    0.000s  (  0.004s elapsed)

由于Windows,使用RTS报告。由于不相关而对某些行进行了修剪-它们是其他GC数据,或仅执行的一部分的测量值,总计加起来为0.004s(或更短)。这也不是固定的折叠,因为Haskell实际上并没有做很多事情。如果我们不断折叠自己(main = print 10000,我们的分配就会大大降低:

...Haskell\8.6\Testbed>Primes.exe +RTS -s
10000
47,688 bytes allocated in the heap
Total   time    0.000s  (  0.001s elapsed)

从字面上看,它刚好足以加载运行时,然后发现除了打印数字并退出之外,无需执行任何其他操作。让我们添加车轮分解:

wheel = scanl (+) 7 $ cycle [4, 2, 4, 2, 4, 6, 2, 6]
primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) $ takeWhile (<85600) wheel

Total   time    0.000s  (  0.003s elapsed)

相对于我们参考的main = print 10000减少了大约1/3,但肯定还有更多优化的余地。例如,它实际上停止了在其中执行GC的工作,而通过微调不应该有任何堆使用。由于某种原因,在此处进行概要分析实际上会将运行时缩短到2毫秒:

Tue Nov 12 21:13 2019 Time and Allocation Profiling Report  (Final)

   Primes.exe +RTS -p -RTS

total time  =        0.00 secs   (2 ticks @ 1000 us, 1 processor)
total alloc =     967,120 bytes  (excludes profiling overheads)

我现在将保持现状,我很确定随机抖动将开始占主导地位。

答案 21 :(得分:0)

我可以给您一些提示,您必须加以实施。

  1. 对于每个数字,获取该数字的一半。例如。对于检查21,仅将其除以2-10即可得到余数。
  2. 如果它是奇数,则只能除以奇数,反之亦然。例如21,只除以3、5、7、9。

到目前为止,我所掌握的最有效的方法。

答案 22 :(得分:0)

我花了一些时间编写计算大量素数的程序,这是我用来计算包含第一个1.000.000.000素数的文本文件的代码。它是德语,但有趣的部分是方法calcPrimes()。素数存储在名为Primzahlen的数组中。我建议使用64位CPU,因为计算是64位整数。

import java.io.*;
class Primzahlengenerator {
    long[] Primzahlen;
    int LastUnknown = 2;
    public static void main(String[] args)  {
        Primzahlengenerator Generator = new Primzahlengenerator();
        switch(args.length) {
            case 0:  //Wenn keine Argumente übergeben worden:
                Generator.printHelp(); //Hilfe ausgeben
                return; //Durchfallen verhindern
            case 1:
                try {
                    Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()];
                }
                catch (NumberFormatException e) {
                    System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. \"Tausend\", sondern in Ziffern z.B. \"1000\" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben
                    Generator.printHelp();                    //Generelle Hilfe ausgeben
                    return;
                }
                break;//dutchfallen verhindern

            case 2:
                switch (args[1]) {
                    case "-l":
                        System.out.println("Sie müsen auch eine Datei angeben!"); //Hilfemitteilung ausgeben
                        Generator.printHelp();                                    //Generelle Hilfe ausgeben
                        return;
                }
                break;//durchfallen verhindern
            case 3:
                try {
                    Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()];
                }
                catch (NumberFormatException e) {
                    System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. \"Tausend\", sondern in Ziffern z.B. \"1000\" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben
                    Generator.printHelp();                      //Generelle Hilfe ausgeben
                    return;
                }
                switch(args[1]) {
                    case "-l":
                        Generator.loadFromFile(args[2]);//Datei Namens des Inhalts von Argument 3 lesen, falls Argument 2 = "-l" ist
                        break;
                    default:
                        Generator.printHelp();
                        break;
                }
                break;
            default:
                Generator.printHelp();
                return;
        }
        Generator.calcPrims();
    }
    void printHelp() {
        System.out.println("Sie müssen als erstes Argument angeben, die wieviel ersten Primzahlen sie berechnen wollen.");   //Anleitung wie man das Programm mit Argumenten füttern muss
        System.out.println("Als zweites Argument können sie \"-l\" wählen, worauf die Datei, aus der die Primzahlen geladen werden sollen,");
        System.out.println("folgen muss. Sie muss genauso aufgebaut sein, wie eine Datei Primzahlen.txt, die durch den Aufruf \"java Primzahlengenerator 1000 > Primzahlen.txt\" entsteht.");
    }
    void loadFromFile(String File) {
        // System.out.println("Lese Datei namens: \"" + File + "\"");
        try{
            int x = 0;
            BufferedReader in = new BufferedReader(new FileReader(File));
            String line;
            while((line = in.readLine()) != null) {
                Primzahlen[x] = new Long(line).longValue();
                x++;
            }
            LastUnknown = x;
        } catch(FileNotFoundException ex) {
            System.out.println("Die angegebene Datei existiert nicht. Bitte geben sie eine existierende Datei an.");
        } catch(IOException ex) {
            System.err.println(ex);
        } catch(ArrayIndexOutOfBoundsException ex) {
            System.out.println("Die Datei enthält mehr Primzahlen als der reservierte Speicherbereich aufnehmen kann. Bitte geben sie als erstes Argument eine größere Zahl an,");
            System.out.println("damit alle in der Datei enthaltenen Primzahlen aufgenommen werden können.");
            }
        /* for(long prim : Primzahlen) {
            System.out.println("" + prim);
        } */
        //Hier soll code stehen, der von der Datei mit angegebenem Namen ( Wie diese aussieht einfach durch angeben von folgendem in cmd rausfinden:
        //java Primzahlengenerator 1000 > 1000Primzahlen.txt
        //da kommt ne textdatei, die die primzahlen enthält. mit Long.decode(String ziffern).longValue();
        //erhält man das was an der entsprechenden stelle in das array soll. die erste zeile soll in [0] , die zweite zeile in [1] und so weiter.
        //falls im arry der platz aus geht(die exception kenn ich grad nich, aber mach mal:
        //int[] foo = { 1, 2, 3};
        //int bar = foo[4];
        //dann kriegst ne exception, das ist die gleiche die man kriegt, wenn im arry der platzt aus geht.
    }
    void calcPrims() {
        int PrimzahlNummer = LastUnknown;
        // System.out.println("LAstUnknown ist: " + LastUnknown);
        Primzahlen[0] = 2;
        Primzahlen[1] = 3;
        long AktuelleZahl = Primzahlen[PrimzahlNummer - 1];
        boolean IstPrimzahl;
        // System.out.println("2");
        // System.out.println("3");
        int Limit = Primzahlen.length;
        while(PrimzahlNummer < Limit) {
            IstPrimzahl = true;
            double WurzelDerAktuellenZahl = java.lang.Math.sqrt(AktuelleZahl);
            for(int i = 1;i < PrimzahlNummer;i++) {
                if(AktuelleZahl % Primzahlen[i] == 0) {
                    IstPrimzahl = false;
                    break;
                }
                if(Primzahlen[i] > WurzelDerAktuellenZahl) break;
            }
            if(IstPrimzahl) {
                Primzahlen[PrimzahlNummer] = AktuelleZahl;
                PrimzahlNummer++;
                // System.out.println("" + AktuelleZahl);
            }
            AktuelleZahl = AktuelleZahl + 2;
        }
        for(long prim : Primzahlen) {
            System.out.println("" + prim);
        }
    }
}

答案 23 :(得分:0)

我已经使用python编写了这个,因为我刚开始学习它,它的工作原理非常好。此代码生成的第10,000个素数与http://primes.utm.edu/lists/small/10000.txt中提到的相同。要检查n是否为素数,请将n除以2sqrt(n)的数字。如果这个数字范围中的任何一个完全划分n那么它就不是素数。

import math
print ("You want prime till which number??")
a = input()
a = int(a)
x = 0
x = int(x)
count = 1
print("2 is prime number")
for c in range(3,a+1):
    b = math.sqrt(c)
    b = int(b)
    x = 0
    for b in range(2,b+1):
        e  = c % b
        e = int(e)
        if (e == 0):
            x = x+1
    if (x == 0):
        print("%d is prime number" % c)
        count = count + 1
print("Total number of prime till %d is %d" % (a,count))

答案 24 :(得分:0)

这里是我做的代码:

enter code here
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT*/   

unsigned long int n;

int prime(unsigned long int);

scanf("%ld",&n);

unsigned long int val;

for(unsigned long int i=0;i<n;i++)
{
    int flag=0;

    scanf("%ld",&val);

    flag=prime(val);

    if(flag==1)
        printf("yes\n");

    else
        printf("no\n");
}

return 0;

}

int prime(unsigned long int n)
{

if(n==2) return 1;

else if (n == 1||n%2==0)  return 0;

for (unsigned long int i=3; i<=sqrt(n); i+=2)
    if (n%i == 0)
        return 0;

return 1;
}

答案 25 :(得分:0)

在Javascript中使用Array.prototype.find()方法。 2214.486 ms

function isPrime (number) {

  function prime(element) {
    let start = 2;
    while (start <= Math.sqrt(element)) {
      if (element % start++ < 1) {
        return false;
      }
    }
    return element > 1;
  }

  return [number].find(prime)

}

function logPrimes (n) {

  let count = 0
  let nth = n

  let i = 0
  while (count < nth) {
    if (isPrime(i)) {
      count++
      console.log('i', i) //NOTE: If this line is ommited time to find 10,000th prime is 121.157ms
      if (count === nth) {
        console.log('while i', i)
        console.log('count', count)
      }
    }
    i++
  }

}

console.time(logPrimes)

logPrimes(10000)

console.timeEnd(logPrimes) // 2214.486ms

答案 26 :(得分:0)

def compute_primes(bound):
"""
Return a list of the prime numbers in range(2, bound)
Implement the Sieve of Eratosthenes
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
"""
primeNumber = [True for i in range(bound + 1)]
start_prime_number = 2
primes = []
while start_prime_number * start_prime_number <=bound:
    # If primeNumber[start_prime_number] is not changed, then it is a prime
    if primeNumber[start_prime_number]:
        # Update all multiples of start_prime_number
        for i in range(start_prime_number * start_prime_number, bound + 1, start_prime_number):
            primeNumber[i] = False
    start_prime_number += 1

# Print all prime numbers
for start_prime_number in range(2, bound + 1):
    if primeNumber[start_prime_number]:
        primes.append(start_prime_number)

return primes

print(len(compute_primes(200)))

print(len(compute_primes(2000)))

答案 27 :(得分:0)

我一直在寻找素数大约一年。这是我发现最快的:

import static java.lang.Math.sqrt;
import java.io.PrintWriter;
import java.io.File;
public class finder {
    public static void main(String[] args) {
        primelist primes = new primelist();
        primes.insert(3);
        primes.insert(5);
        File file = new File("C:/Users/Richard/Desktop/directory/file0024.txt");
        file.getParentFile().mkdirs();
        long time = System.nanoTime();
        try{
            PrintWriter printWriter = new PrintWriter ("file0024.txt"); 
            int linenum = 0;
            printWriter.print("2");
            printWriter.print (" , ");
            printWriter.print("3");
            printWriter.print (" , ");
            int up;
            int down;           
            for(int i =1; i<357913941;i++){//
                if(linenum%10000==0){
                    printWriter.println ("");
                    linenum++;
                }
                down = i*6-1;
                if(primes.check(down)){
                    primes.insert(down);
                    //System.out.println(i*6-1);
                    printWriter.print ( down );
                    printWriter.print (" , ");
                    linenum++;  
                }
                up = i*6+1;
                if(primes.check(up)){
                    primes.insert(up);
                    //System.out.println(i*6+1);
                    printWriter.print ( up );
                    printWriter.print (" , ");
                    linenum++;  
                }
            }
            printWriter.println ("Time to execute");
            printWriter.println (System.nanoTime()-time);
            //System.out.println(primes.length);
            printWriter.close ();
        }catch(Exception e){}
    } 
}
class node{
    node next;
    int x;
    public node (){
        node next;
        x = 3;
    }
    public node(int z) {
        node next;
        x = z;
    }
}
class primelist{
    node first;
    int length =0;
    node current;
    public void insert(int x){
        node y = new node(x);
        if(current == null){
            current = y;
            first = y;
        }else{
            current.next = y;
            current = y;
        }
        length++;
    }
    public boolean check(int x){
        int p = (int)sqrt(x);
        node y = first;
        for(int i = 0;i<length;i++){
            if(y.x>p){
                return true;
            }else if(x%y.x ==0){
                return false;
            }
            y = y.next;
        }
        return true;
    }
}

1902465190909纳秒从21开始到达2147483629。

答案 28 :(得分:-1)

using System;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            int n, i = 3, j, c;
            Console.WriteLine("Please enter your integer: ");
            n = Convert.ToInt32(Console.ReadLine());
            if (n >= 1)
            {
                Console.WriteLine("First " + n + " Prime Numbers are");
                Console.WriteLine("2");
            }
            for(j=2;j<=n;)
            {
                for(c=2;c<=i-1;c++)
                {
                    if(i%c==0)
                        break;
                }
                    if(c==i)
                    {
                        Console.WriteLine(i);
                        j++;
                    }
                    i++;                                
            }
            Console.Read();
        }
    }
}