1. 程式人生 > >素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)

素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)

lin ++ lse 大於 所有 void ont null -a

問題:

  • 不超過2000的素數有哪些?
  • 她的QQ號是素數嗎?

解決:

已知:

  1. 1不是素數
  2. 2是素數
  3. 大於2的偶數不是素數
  4. 大於2的素數是奇數
  5. 當自然數k > 1時,素數的k被數不是素數

策略:

  1. 采用大型布爾數組,其元素取值只有0(FALSE_FLAG)和1(TRUE_FLAG)兩種
  2. 用大型布爾數組中下標為i的位置代表奇數(2*i + 1)
  3. 斷定(2*i + 1)為素數當且僅當在大型布爾數組中下標為i的位置的元素的值為1(TRUE_FLAG)

編碼:

頭文件:prime_number.h

 1 #ifndef PRIME_NUMBER_H
 2 #define PRIME_NUMBER_H
 3
4 typedef enum{FALSE_FLAG, TRUE_FLAG} BOOLEAN_FLAG; // 當作布爾類型來用 5 typedef unsigned long long COUNT, PRIME_INTEGER; // 制定素數數組的下標數據類型和元素數據類型 6 7 typedef struct { 8 BOOLEAN_FLAG *boolean_flag_array; 9 COUNT count; 10 }BOOLEAN_FLAG_ARRAY; // 大型布爾數組 11 12 /************************************全局常量的聲明***********************************
*/ 13 14 extern const 15 BOOLEAN_FLAG_ARRAY EMPTY_BOOLEAN_FLAG_ARRAY; // 空BOOLEAN_FLAG_ARRAY 16 17 extern const char 18 *PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE, // 素數數組的元素的輸出格式符 19 *PRINT_FORMAT_STRING_OF_COUNT_TYPE; // 素數數組的下標的輸出格式符 20 21 /**************************************方法的聲明*************************************
*/ 22 23 /*獲取upper_limit以內的素數的索引數組*/ 24 BOOLEAN_FLAG_ARRAY getBooleanFlagArrayFor(PRIME_INTEGER upper_limit); 25 26 /*格式化地打印upper_limit以內的全部素數*/ 27 void printPrimeIntegerArrayBellow(PRIME_INTEGER upper_limit); 28 29 /*判斷一個給定的數是否為素數*/ 30 BOOLEAN_FLAG isPrimeInteger(PRIME_INTEGER n); 31 32 #endif

源文件:prime_number.c

  1 #include "prime_number.h"
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 
  5 /************************************全局常量的定義************************************/
  6 
  7 const BOOLEAN_FLAG_ARRAY 
  8 EMPTY_BOOLEAN_FLAG_ARRAY = { NULL, 0 }; // 空BOOLEAN_FLAG_ARRAY
  9 
 10 const char 
 11 *PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE = "%3llu", // 制定素數數組的元素的輸出格式符
 12 *PRINT_FORMAT_STRING_OF_COUNT_TYPE = "%02llu"; // 制定素數數組的下標的輸出格式符
 13 
 14 /**************************************方法的定義**************************************/
 15 
 16 /*獲取upper_limit以內的素數的索引數組*/
 17 BOOLEAN_FLAG_ARRAY
 18 getBooleanFlagArrayFor(PRIME_INTEGER upper_limit) {
 19     /*不存在小於2的素數*/
 20     if (upper_limit < 2) {
 21         return EMPTY_BOOLEAN_FLAG_ARRAY;
 22     }
 23     /*
 24     **upper_limit以內至多有max_count個奇數,
 25     **且其中的第一個奇數(用下標為0的位置代表)是1,已知1不是素數,
 26     **於是相應地開辟含有max_count個位置的boolean_flag_array,
 27     **且boolean_flag_array的第一個位置僅起占位作用,
 28     **在1以後的奇數序列為3, 5, 7, 9, 11, 13 ...
 29     **依次用下標為1, 2, 3, 4, 5, 6 ...的位置來代表
 30     **這樣的話,下標為i的位置代表的奇數就是(2*i + 1)
 31     **下標為i的位置的BOOLEAN_FLAG值就用來指示該位置代表的奇數是否為素數
 32     */
 33     COUNT max_count = (upper_limit + 1) / 2;
 34     BOOLEAN_FLAG *boolean_flag_array = (BOOLEAN_FLAG *)malloc(max_count * sizeof(BOOLEAN_FLAG));
 35     COUNT i = 1, j;
 36     while (i < max_count) {
 37         /*先把第一個位置以後的所有位置標記為TRUE_FLAG*/
 38         boolean_flag_array[i++] = TRUE_FLAG;
 39     }
 40     for (i = 1; i < max_count; ++i) {
 41         if (boolean_flag_array[i] == FALSE_FLAG) {
 42             continue; // 它的倍數已經被劃掉了
 43         }
 44         for (j = i; (j += 2 * i + 1) < max_count; ) {
 45             /*(k>1), 素數的k倍數必然是合數,就標記為FALSE_FLAG*/
 46             boolean_flag_array[j] = FALSE_FLAG;
 47         }
 48     }
 49 
 50     /*釋放boolean_flag_array末尾可能存在的連續多個FALSE_FLAG*/
 51     for (i = max_count; boolean_flag_array[--i] == FALSE_FLAG;);
 52     boolean_flag_array = (BOOLEAN_FLAG *)realloc(boolean_flag_array, (i + 1) * sizeof(BOOLEAN_FLAG));
 53     
 54     return (BOOLEAN_FLAG_ARRAY) { boolean_flag_array, max_count };
 55 }
 56 
 57 /*以“PrimeIntegerArray(index) = prime_integer”並換行的格式打印素數元素*/
 58 void 
 59 printPrimeIntegerElement(COUNT index, PRIME_INTEGER prime_integer) {
 60     printf("PrimeIntegerArray(");
 61     printf(PRINT_FORMAT_STRING_OF_COUNT_TYPE, index);
 62     printf(") = ");
 63     printf(PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE, prime_integer);
 64     printf("\n");
 65 }
 66 
 67 /*格式化地打印upper_limit以內的全部素數*/
 68 void
 69 printPrimeIntegerArrayBellow(PRIME_INTEGER upper_limit) {
 70     /**/
 71     if (upper_limit < 2) {
 72         printf("EMPTY_BOOLEAN_FLAG_ARRAY\n");
 73         return;
 74     }
 75     /*至少有一個*/
 76     printPrimeIntegerElement(0, 2);
 77     if (upper_limit == 2) {
 78         return;
 79     }
 80     /*有好多個呢*/
 81     BOOLEAN_FLAG_ARRAY piia = getBooleanFlagArrayFor(upper_limit);
 82     COUNT i = 1, j = 1;
 83     while (i < piia.count) {
 84         if (piia.boolean_flag_array[i] == TRUE_FLAG) {
 85             /*這裏的i是boolean_flag_array數組下標,它的特性如下:
 86             **(1)在boolean_flag_array數組中下標為i的位置代表的奇數就是(2*i + 1)
 87             **(2)斷定(2*i + 1)為素數當且僅當在boolean_flag_array數組中下標為i的位置的BOOLEAN_FLAG為TRUE_FLAG
 88 
 89             **而這裏的j是要輸出的素數數組的下標
 90             **只有確實輸出了一個素數,j才加1
 91             */
 92             printPrimeIntegerElement(j++, 2 * i + 1);
 93         }
 94         ++i;
 95     }
 96 }
 97 
 98 /*判斷一個給定的數是否為素數*/
 99 BOOLEAN_FLAG
100 isPrimeInteger(PRIME_INTEGER n) {
101     /*已知2是素數*/
102     if (n == 2) {
103         return TRUE_FLAG;
104     }
105     /*小於2的數以及大於2的偶數都不是素數*/
106     if (n < 2 || n % 2 == 0) {
107         return FALSE_FLAG;
108     }
109     /*
110     **大於2的奇數在boolean_flag_array中對應的位置的下標為(n - 1) / 2
111     **該位置的BOOLEAN_FLAG值就指示著對應的奇數是否確實為素數
112     */
113     return getBooleanFlagArrayFor(n).boolean_flag_array[(n - 1) / 2];
114 }

源文件:main.c

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

運行:

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

技術分享圖片

GCC version 7.3.1 on Manjaro Linux

技術分享圖片

素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)