1. Prime number a
nd related
Prime, also known as Prime, in a natural number greater than 1, except 1 and this integer itself, can not be divisible by other natural numbers. A number larger than 1, but not prime, is called composite. 1 and 0 are neither primes nor composite. The basic theorem of arithmetic proves that each positive integer greater than 1 can be written as the product of a prime number, and the form of this product is unique.
2, Trial Division to find prime numbers
Algorithm Description: According to the definition of prime number, we can not be divided into 1 and the integers of the integer is prime. So, we can tell whether a prime is a prime number, just see if it can be 2~sqrt (i) between the numbers of integers. And all the primes in n is a cyclic repetition of the above process.
The C language implementation is shown below.
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <malloc.h>
//Trial Division
#define NUM 10000
int test_prime (int n)
{
int count = 0;
int I, J;
int *num = (int *) malloc (sizeof (int) * n);
num[count++] = 2;
for (i = 3; l <= N; i++)
{for
(j = 2; J <= sqrt (i); + j)
{
if (i% j = 0)
{
break;}
}
if (J > sqrt (i))
{
num[count++] = i;
}
}
Free (num);
return count;
}
int main ()
{
int count;
clock_t Start,end;
start = Clock ();
Count = Test_prime (NUM);
end = Clock ();
printf ("Number of primes in%d:%d, total time elapsed:%d milliseconds \ n", NUM, Count, End-start);
return 0;
}
when the data is very large, the time consumption increases relatively fast.
3, Trial Division optimization scheme
Careful study of trial division, you can find the following problems:
1> in the cyclic condition repeated call sqrt (i), which is obviously a waste of time;
2> Judging primes, really need to take 2-sqrt (i) between all the integers removed. We know that composite can be decomposed into several prime numbers, so as long as the prime numbers between 2-sqrt (i) cannot be divisible by I, the c language implementation is as follows.
// Find all prime numbers in N
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <malloc.h>
// try division
#define NUM 1000000
int Test_prime (int n)
{
int count = 0;
int i, j, k, stop;
// Allocate space
int * num = (int *) malloc (sizeof (int) * n);
// 2 must be a prime number
num [count ++] = 2;
stop = 0;
for (i = 3; i <= n; i ++)
{
// It is inefficient to repeatedly call sqrt in a loop, so k is introduced
k = (int) sqrt (i);
// Stop is used to count the number of prime numbers less than the current k value
while (num [stop] <= k && stop <count)
{
stop ++;
}
for (j = 0; j <stop; j ++)
{
if (i% num [j] == 0)
{
// i cannot be divisible by primes between 2-sqrt (i)
break;
}
}
if (j == stop)
{
num [count ++] = i;
}
}
free (num);
return count;
}
int main ()
{
int count;
clock_t start, end;
start = clock ();
count = Test_prime (NUM);
end = clock ();
printf ("The prime numbers in% d are:% d, the total time is:% d milliseconds \ n", NUM, count, end-start);
return 0;
}
Compared to the algorithm before optimization, TIME provides a lot. In particular, the amplitude of the time growth curve becomes smaller, and the greater the N value, the optimized algorithm is more efficient than the optimized algorithm.
4, composite filtration screening method
Algorithm Description: By the definition of prime numbers, the prime number n cannot be divisible by any integer between N-1, and conversely, as long as N, which can be divisible by any integer between N-1, is not a prime number. Therefore, we use the exclusion method: is the number of all numbers within N, as long as one by one to remove the value of a multiple of N-1, the rest is prime. The C language implementation is shown below.
Merge filter
#include <stdio.h>
#include <time.h>
#include <math.h>
#include < Malloc.h>
//Trial Division
#define NUM 10000
int test_prime (int n)
{
int count = 0;
int I, J;
Allocate space, the reason is n+1, because a waste of a num[0]
char *num = (char *) malloc (sizeof (char) * (n + 1));
Initialize prime number tag for
(i = 2; i<= n; i++)
{
num[i] = 1;
}
The filter composite for
(i = 2; I <= n-1; i++)
{for
(j = 2; J * I <= N; j + +)
{
//i*j is multiplied by two integers by N-1. Obviously not prime
num[i*j] = 0;
}
}
Number of statisticians for
(i = 2; i<= n; i++)
{
if (1 = = Num[i])
{
count++;
}
}
Free (num);
return count;
}
int main ()
{
int count;
clock_t Start,end;
start = Clock ();
Count = Test_prime (NUM);
end = Clock ();
printf ("Number of primes in%d:%d, total time elapsed:%d milliseconds \ n", NUM, Count, End-start);
return 0;
}
Many of the above procedures have adopted a relatively inefficient approach, in order to compare with the optimization of the later, this is the same as I do beginners commonly used version, therefore, to learn to optimize.
5, Combined Screening method optimization scheme
The problem with the above algorithm is:
1> in the outer layer of the loop, it needs to be carried out to n-1. No, because the number between n/2-(n-1) is obviously not divisible by N,
2> in the inner loop is obviously inefficient, considering that the addition and subtraction of the computer is faster than multiplication, it is possible to consider variable multiplication as additive;
3> in the process of changing the flag in the loop, In fact, a very large number of repeated calculations, such as 6 = 2*3 = 3*2, is repeated zero, so can be avoided; C language implementation is as follows.
// Optimization scheme of combined screening method
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <malloc.h>
#define NUM 300000
int Test_prime (int n)
{
int count = 0;
int i, j;
// Allocate space
char * num = (char *) malloc (sizeof (char) * (n + 1));
// Initialize prime numbers
num [2] = 1;
// Note that here is i <n, i <= n in the above example
for (i = 3; i <n; i ++)
{
num [i ++] = 1;
num [i] = 0; // Even numbers are naturally not prime numbers
}
// If n is odd
if (n% 2! = 0)
{
num [n] = 1;
}
// Filter from 3, because multiples of 2 are removed during initialization
for (i = 3; i <= n / 2; i ++)
{
if (0 == num [i])
{
continue;
}
// Filter from 2 times i
for (j = i + i; j <= n; j + = i)
{
num [j] = 0;
}
}
// Count the number of primes
for (i = 2; i <= n; i ++)
{
if (1 == num [i])
{
count ++;
}
}
free (num);
return count;
}
int main ()
{
int count;
clock_t start, end;
start = clock ();
count = Test_prime (NUM);
end = clock ();
printf ("The prime numbers in% d are:% d, the total time is:% d milliseconds \ n", NUM, count, end-start);
return 0;
}
Really much faster than before, optimization really can bring time to improve, so I am very happy. Later I thought about adding a supplement: If I optimize the red part of the code above, as shown below.
Filter starting from 3, because, a multiple of 2 in the initialization is removed for the for
(i = 3; I <= n/2; i = i + 2)
{
//In this case, you already have a function that rejects even
if (0 = = Num[i]){
continue;
}
Starting from I twice Times filter
for (j = i + i; J <= n;j+=i)
{
//is directly assigned to the value fast. Or is it here to add judgment fast? I don't know. Solving..
if (j% 2 = = 0)
{
continue;
}
else
{
Num[j] = 0;}}
}
The first part of the red, I will be the original odd and even to judge, changed to only the odd number of judgments, the second part of the red, I will be odd multiples of the direct culling of an even number, to the odd multiples of the assignment; The test for num = 300000 .
The time is only 7 milliseconds, and the time is faster than num = 300000 before optimization.
// Optimization scheme of combined screening method
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <malloc.h>
#include <string.h>
#define NUM 10000
int Test_prime (int n)
{
int i, j;
// Prime number statistics
int count = 0;
// Allocate space for prime numbers, understand why +1, because a num [0] is wasted
char * num = (char *) malloc (n + 1);
// Why use it, please study the following carefully
int mpLen = 2 * 3 * 5 * 7 * 11 * 13;
char magicPattern [2 * 3 * 5 * 7 * 11 * 13];
// Strange code, think.
for (i = 0; i <mpLen; i ++)
{
magicPattern [i ++] = 1;
magicPattern [i ++] = 0;
magicPattern [i ++] = 0;
magicPattern [i ++] = 0;
magicPattern [i ++] = 1;
magicPattern [i] = 0;
}
for (i = 4; i <= mpLen; i + = 5)
{
magicPattern [i] = 0;
}
for (i = 6; i <= mpLen; i + = 7)
{
magicPattern [i] = 0;
}
for (i = 10; i <= mpLen; i + = 11)
{
magicPattern [i] = 0;
}
for (i = 12; i <= mpLen; i + = 13)
{
magicPattern [i] = 0;
}
// new initialization method, kill all multiples of 2, 3, 5, 7, 11, 13
// And use memcpy to batch process mpLen magicPattern
int remainder = n% mpLen;
char * p = num + 1;
char * pstop = p + n-remainder;
while (p <pstop)
{
memcpy (p, magicPattern, mpLen);
p + = mpLen;
}
if (remainder> 0)
{
memcpy (p, magicPattern, remainder);
}
num [2] = 1;
num [3] = 1;
num [5] = 1;
num [7] = 1;
num [11] = 1;
num [13] = 1;
// Filter from 17 because multiples of 2,3,5,7,11,13 have been removed
// to n / 13
int stop = n / 13;
for (i = 17; i <= stop; i ++)
{
// i is composite
if (0 == num [i])
{
continue;
}
// Filter from 17 times of i
int step = i * 2;
for (j = i * 17; j <= n; j + = step)
{
num [j] = 0;
}
}
// Count the number of primes
for (i = 2; i <= n; i ++)
{
if (num [i])
{
count ++;
}
}
// release memory
free (num);
return count;
}
int main ()
{
int count;
clock_t start, end;
start = clock ();
count = Test_prime (NUM);
end = clock ();
printf ("The prime numbers in% d are:% d, the total time is:% d milliseconds \ n", NUM, count, end-start);
return 0;
}
To tell the truth, this kind of thought is really great, now I can not think of, thank the author, let me have a broader insight.
7. Other
In addition to the above several algorithms, such as the Rabin Miller Prime test algorithm, it is difficult to feel this algorithm, first take a good look, and so understand, and then make up.
Through today's tangled, for the prime number has a more profound understanding and understanding, feel that they are much worse, need more efforts. In addition, thanks to the author of Baidu Space Doforfun_net, gave me a great inspiration, learned a lot.