素數序列的生成及其應用(採用了自研的高效算法)

問題:

  • 2000之內的素數有哪些?
  • 她的手機號是素數嗎?

思路:

問題歸類:

  • 怎樣獲取n之內的全部素數呢?
  • 怎樣高效地斷定一個正整數是否爲素數呢?

假設已知:

第一個素數是2,第二個素數是3;算法

判定某正整數n確實爲素數的依據是:當且僅當 若不超過n的算數平方根的全部素數都不能整除n,那麼就判定n爲素數數組

醞釀策略:

先解決「獲取n之內的全部素數」的問題,而後應用其結果來解決「高效地斷定一個正整數是否爲素數」的問題。spa

從第三個待定素數開始,之後老是把下一個候選素數的初始值取爲當前已知的最後一個素數(必爲奇數)
而後執行下述循環
LOOP
EXIT WHEN 候選素數超過n;
把該待定素數(爲奇數)的值更新爲其下一個奇數的值:prime_number_candidate += 2;
探測該待定素數是否確實爲素數:如果,則把它做爲正式的素數寫到素數數組中下一個素數的位置上;不然,直接去繼續下一輪循環。

END LOOP3d

代碼實踐:

頭文件:prime_number.h code

 1 #ifndef PRIME_NUMBER_H  2 #define PRIME_NUMBER_H
 3 
 4 /*制定 素數數組的元素以及計數下標的數據類型*/
 5 typedef unsigned long long PRIME_INTEGER_TYPE, PRIME_INTEGER_ARRAY_COUNT_TYPE;  6 
 7 /*制定 容量可動態調整的素數數組容器數據類型*/
 8 typedef struct {  9     PRIME_INTEGER_TYPE *prime_integer_array; // 容量可動態調整的素數數組
10     PRIME_INTEGER_ARRAY_COUNT_TYPE count; // 素數數組中元素的數目
11 }PRIME_INTEGER_ARRAY_TYPE; 12 
13 /************************************全局常量的聲明************************************/
14 extern const PRIME_INTEGER_ARRAY_TYPE EMPTY_PRIME_INTEGER_ARRAY; 15 extern const char *PRIME_INTEGER_TYPE_PRINT_FORMAT_STRING, *PRIME_INTEGER_ARRAY_COUNT_TYPE_PRINT_FORMAT_STRING; 16 
17 /**************************************方法的聲明**************************************/
18 
19 /*獲取upper_limit之內的素數數組*/
20 PRIME_INTEGER_ARRAY_TYPE getPrimeIntegerArrayBelow(PRIME_INTEGER_TYPE upper_limit); 21 
22 /*格式化地打印upper_limit之內的所有素數*/
23 void printPrimeIntegerArrayBelow(PRIME_INTEGER_TYPE upper_limit); 24 
25 /*判斷一個給定的數是否爲素數*/
26 int isPrimeInteger(PRIME_INTEGER_TYPE n); 27 
28 #endif

 

源文件:prime_number.c blog

 1 #include "prime_number.h"
 2 #include <stdlib.h>  3 #include <stdio.h>  4 #include <math.h>  5 
 6 /************************************全局常量的定義************************************/
 7 const PRIME_INTEGER_ARRAY_TYPE EMPTY_PRIME_INTEGER_ARRAY = {NULL, 0}; // 空素數數組
 8 const char *PRIME_INTEGER_TYPE_PRINT_FORMAT_STRING = "%2llu", *PRIME_INTEGER_ARRAY_COUNT_TYPE_PRINT_FORMAT_STRING = "%02llu"; // 設置打印素數數組時元素及下標的輸出格式符
 9 
 10 /**************************************方法的定義**************************************/
 11 
 12 /*獲取素數探測者的上限*/
 13 PRIME_INTEGER_TYPE getProberUpperLimitFor(PRIME_INTEGER_TYPE prime_integer_candidate) {  14     /*取素數候選者的算術平方根的去尾近似值做爲用來探測它是否確實爲素數的素數探測者的上限*/
15 return llroundl(sqrtl(prime_integer_candidate*1.0));
16 } 17 18 /*獲取upper_limit之內的素數數組*/ 19 PRIME_INTEGER_ARRAY_TYPE getPrimeIntegerArrayBelow(PRIME_INTEGER_TYPE upper_limit) { 20 /*最小的素數爲2,所以在2以前的素數數組爲空素數數組*/ 21 if (upper_limit < 2) { 22 return EMPTY_PRIME_INTEGER_ARRAY; 23 } 24 /*在upper_limit之內頂多有max_count個素數,*/ 25 PRIME_INTEGER_ARRAY_COUNT_TYPE max_count = (upper_limit + 1) / 2; 26 /*開闢足夠的空間用來容納upper_limit之內的所有素數*/ 27 PRIME_INTEGER_TYPE *prime_integer_array = (PRIME_INTEGER_TYPE *)malloc((size_t)(max_count) * sizeof(PRIME_INTEGER_TYPE)); 28 if (prime_integer_array == NULL) { 29 printf("Failed when doing malloc.\n"); 30 exit(1); 31 } 32 /*裝載第一個素數*/ 33 prime_integer_array[0] = 2; 34 if (upper_limit == 2) { 35 return (PRIME_INTEGER_ARRAY_TYPE) { prime_integer_array, 1 }; 36 } 37 /*裝載第二個素數*/ 38 prime_integer_array[1] = 3; 39 if (upper_limit <= 4) { 40 return (PRIME_INTEGER_ARRAY_TYPE) { prime_integer_array, 2 }; 41 } 42 /*後續素數均經過算法來求取*/ 43 PRIME_INTEGER_ARRAY_COUNT_TYPE i = 1; // 接下來會用做while循環的步進變量 44 PRIME_INTEGER_TYPE next_prime_integer_candidate = prime_integer_array[i], prober_upper_limit; 45 int flag = 1; // 接下來會把flag看成布爾變量來用 46 PRIME_INTEGER_ARRAY_COUNT_TYPE j; // 接下來會用做內部for循環的步進變量 47 /*僅裝載upper_limit之內的所有素數,若已裝載完畢就退出循環*/ 48 while (/*i < max_count && */(next_prime_integer_candidate += 2) <= upper_limit) { 49 /*取下一個素數候選者的算術平方根的去尾近似值做爲用來探測下一個素數候選者是否確實爲素數的探測者的上限*/ 50 prober_upper_limit = getProberUpperLimitFor(next_prime_integer_candidate); 51 /*從第二個素數開始,依次用prober_upper_limit之內的素數來探測下一個素數候選者是否確實爲素數*/ 52 for (j = 1; 53 /*j <= i &&*/ 54 /*只需用prober_upper_limit之內的素數來探測*/ 55 (flag = prime_integer_array[j] <= prober_upper_limit) 56 && 57 /*當且僅當prober_upper_limit之內的全部素數都不能整除下一個素數候選者時,才判定下一個素數候選者確實爲素數*/ 58 (next_prime_integer_candidate % prime_integer_array[j] != 0); 59 ++j) 60 ; 61 /* 退出上面的for循環的緣由有兩種: 62 ** (1)prober_upper_limit之內的素數都已經做爲探測者使用過了也沒可否認下一個素數候選者 63 ** (2)下一個素數候選者被prober_upper_limit之內的某個素數整除了*/ 64 /*如果由於緣由(1)而退出上面的for循環,那麼就可判定下一個素數候選者確實爲素數*/ 65 if (flag == 0) { 66 /*把下一個素數候選者正式做爲下一個素數寫入素數數組的下一個位置中*/ 67 prime_integer_array[++i] = next_prime_integer_candidate; 68 /*最終i的值也就是prime_integer_array的最大有效下標*/ 69 } 70 } 71 /*已知確切的素數個數,那麼就能夠把prime_integer_array所佔的空間收縮到恰到好處的大小吧*/ 72 prime_integer_array = (PRIME_INTEGER_TYPE *)realloc(prime_integer_array, (size_t)(i + 1)* sizeof(PRIME_INTEGER_TYPE)); 73 return (PRIME_INTEGER_ARRAY_TYPE) { prime_integer_array, i + 1 }; 74 } 75 76 /*格式化地打印upper_limit之內的所有素數*/ 77 void printPrimeIntegerArrayBelow(PRIME_INTEGER_TYPE upper_limit) { 78 PRIME_INTEGER_ARRAY_TYPE pia = getPrimeIntegerArrayBelow(upper_limit); 79 if (pia.count == 0) { 80 printf("EMPTY_PRIME_INTEGER_ARRAY\n"); 81 } 82 else { 83 PRIME_INTEGER_ARRAY_COUNT_TYPE i = 0; 84 while (i < pia.count) { 85 printf("PrimeIntegerArray("); 86 printf(PRIME_INTEGER_ARRAY_COUNT_TYPE_PRINT_FORMAT_STRING, i); 87 printf(") = "); 88 printf(PRIME_INTEGER_TYPE_PRINT_FORMAT_STRING, pia.prime_integer_array[i]); 89 printf("\n"); 90 ++i; 91 } 92 } 93 } 94 95 /* 96 **判斷一個給定的數是否爲素數 97 **思路:當且僅當 若不超過其算數平方根的全部素數都不能整除n,那麼判定n爲素數; 98 */ 99 int isPrimeInteger(PRIME_INTEGER_TYPE n) { 100 if (n < 2) { 101 return 0; 102 } 103 if (n == 2 || n == 3 || n == 5 || n == 7) { 104 return 1; 105 } 106 if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n % 7 == 0) { 107 return 0; 108 } 109 /*取下一個素數候選者的算術平方根的去尾近似值做爲用來探測下一個素數候選者是否確實爲素數的探測者的上限*/ 110 PRIME_INTEGER_TYPE prober_upper_limit = getProberUpperLimitFor(n); 111 /*生成探測者的上限之內的素數數組*/ 112 PRIME_INTEGER_ARRAY_TYPE pia = getPrimeIntegerArrayBelow(prober_upper_limit); 113 /*在上面的if語句中,2, 3, 5, 7這前4個素數已經用過了,下面直接從素數數組中第五個(其下標爲4)的那個素數開始做爲探測者*/ 114 PRIME_INTEGER_ARRAY_COUNT_TYPE i = 4; 115 while (i < pia.count) { 116 /*一旦被素數數組中的某素數否定,則直接返回「假」(這裏用0表示「假」,用1表示「真」)*/ 117 if (n % pia.prime_integer_array[i] == 0) { 118 return 0; 119 } 120 ++i; 121 } 122 /*程序能執行到這一行,就能確定n確實爲素數。由於若是n不是素數,那麼在上面的while循環中就已經直接return退出了*/ 123 return 1; 124 }

 

源文件:main.cget

1 #include "prime_number.h"
2 #include <stdio.h>
3 
4 int main(int argc, char **argv) { 5     printPrimeIntegerArrayBelow(100); 6     
7 printf("isPrimeInteger(65537) : %s\n", isPrimeInteger(65537) == 1?"Yes":"No"); 8 return 0; 9 }

 

運行展現:

Microsoft Visual Studio Enterprise 2017 version 15.6.6 on Windows 10 Pro 1709

 

GCC version 7.3.1 on Manjaro Linux

相關文章
相關標籤/搜索