zoukankan      html  css  js  c++  java
  • 素数序列的生成及其应用(采用了新学的更高效的算法:布尔标记法 + 倍数淘汰法)

    问题:

    • 不超过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     /*在下一个修订版Version 2.2中做了改动:释放boolean_flag_array末尾可能存在的连续多个FALSE_FLAG。当前版本为2.0,暂且不应用此改动。*/
     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("
    ");
     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
    ");
     73         return;
     74     }
     75     /*至少有一个*/
     76     printPrimeIntegerElement(0, 2);
     77     if (upper_limit == 2) {
     78         return;
     79     }
     80     /*有好多个呢*/
     81     BOOLEAN_FLAG_ARRAY bfa = getBooleanFlagArrayFor(upper_limit);
     82     COUNT i = 1, j = 1;
     83     while (i < bfa.count) {
     84         if (bfa.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
    ", 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

     

  • 相关阅读:
    操作系统开发系列—13.g.操作系统的系统调用 ●
    操作系统开发系列—13.f.Minix的中断处理(暂时忽略)
    操作系统开发系列—13.e.三进程
    操作系统开发系列—13.d.多进程 ●
    操作系统开发系列—解释typedef void (*int_handler) ();
    操作系统开发系列—13.c.进程之中断重入
    操作系统开发系列—13.b.进程之丰富中断处理程序
    操作系统开发系列—13.a.进程 ●
    操作系统开发系列—12.g.在内核中设置键盘中断
    操作系统开发系列—12.f.在内核中添加中断处理 ●
  • 原文地址:https://www.cnblogs.com/yawenunion/p/8886134.html
Copyright © 2011-2022 走看看