筛素数法小结

简介:

筛选素数方法小结:

  最简单的筛素数法方法就是从2开始,将所以2的倍数去掉,然后从3开始,将3的倍数去掉,依次进行下去即可。根据这样很容易写出代码,下面代码就是是筛素数法得到100以内的素数并保存到primes[]数组中。

复制代码
复制代码
 1 const int MAXN = 100;
 2 bool flag[MAXN];
 3 int primes[MAXN / 3], pi;
 4 void GetPrime_1()
 5 {
 6     int i, j;
 7     pi = 0;
 8     memset(flag, false, sizeof(flag));
 9     for (i = 2; i < MAXN; i++)
10         if (!flag[i])
11         {
12             primes[pi++] = i;
13             for (j = i; j < MAXN; j += i)  //剔除待考察数据j的倍数,并置其flag位为true
14                 flag[j] = true;
15         }
16 }
复制代码
复制代码

  可以看出这种会有很多重复访问,如在访问flag[2]和flag[5]时会各访问flag[10]一次。因此最好想方法来减少这种重复访问,让flag[]数组的每个元素只被访问一次。可以这样考虑——简单的筛素数法是利用一个素数的倍数必须不是素数,同样任何一个数与其它所有素数的乘积必然也不是素数(这是因为每个合数必有一个最小素因子)。

      为了试验这种想法,先用2到10之间的数来验证下。

      2,3,4,5,6,7,8,9,10      初始时所以flag都是无标记的。

  第一步 访问2,flag[2]无标记所以将2加入素数表中,然后将2与素数表中的所有数相乘得到的数必定不是素数,2*2=4因此标记flag[4]。

   2,3,4,5,6,7,8,9,10

  第二步 访问3,flag[3]无标记所以将3加入素数表中,将3与素数表中的所有数相乘得到的数必定不是素数,3*2=6,3*3=9因此标记flag[6]和flag[9]。

   2,3,4,5,6,7,8,9,10

  第三步 访问4,flag[4]有标记所以4不加入素数表中,将4与素数表中的所有数相乘得到的数必定不是素数, 4*2=8,4*3=12因此标记flag[8]。

   2,3,4,5,6,7,8,9,10

  第四步 访问5,flag[5]无标记所以将5加入素数表中,将5与素数表中的所有数相乘得到的数必定不是素数,5*2=10,5*3=15因此标记flag[10]。

   2,3,4,5,6,7,8,9,10

  第五步 访问6,flag[6]有标记所以6不加入素数表中,将6与素数表中的所有数相乘得到的数必定不是素数, 6*2=12,6*3=18,6*5=30。

   2,3,4,5,6,7,8,9,10

    后面几步类似,具体代码如下:

复制代码
复制代码
 1 const int MAXN = 100;
 2 bool flag[MAXN];
 3 int primes[MAXN / 3], pi;
 4 void GetPrime_2()
 5 {
 6     int i, j;
 7     pi = 0;
 8     memset(flag, false, sizeof(flag));
 9     for (i = 2; i < MAXN; i++)
10     {
11         if (!flag[i])
12             primes[pi++] = i;  //flag未标记为true,将其加入到素数表中
13         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)  //依次剔除待考察数据与素数表中数据的乘积,并置其flag位为true
14             flag[i * primes[j]] = true;
15     }
16 }
复制代码
复制代码

  这份代码对不对呢?仔细回顾下分析过程,可以发现有些数据还是被访问了多次,这当然不是我们希望的结果,我们的要求是让每个合数仅被它的最小素因子筛去一次。比如12,它的最小素因子是2,所以就只应该被在计算6*2时去访问,而且不应该在计算4*3时去访问,同理18也只应该被在计算9*2时去访问,而且不应该在计算6*3时去访问。

    找到原因后,再来思考如何解决。6*3不行而9*2可以了,是因为6是2的倍数,所以在计算6*2之后就不能再将6与比2大的素数相乘,这些相乘的结果必定会导致重复计算。因此对于任何数来说,如果它是该素数的倍数那么它就不能再与素数表中该素数之后的素数相乘了,如9是3的倍数,所以在9*3之后就不能再去用计算9*5了。因此在代码中再增加一行判断语句:

复制代码
复制代码
 1 const int MAXN = 100;
 2 bool flag[MAXN];
 3 int primes[MAXN / 3], pi;
 4 void GetPrime_2()
 5 {
 6     int i, j;
 7     pi = 0;
 8     memset(flag, false, sizeof(flag));
 9     for (i = 2; i < MAXN; i++)
10     {
11         if (!flag[i])
12             primes[pi++] = i;
13         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
14         {
15             flag[i * primes[j]] = true;
16             if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次
17                 break;
18 }
19     }
20 }
复制代码
复制代码

  想知道这二种筛素数法方法的区别吗?现在对求2到1亿之间的素数进行测试,看看区别到底会有多大,测试代码如下:

复制代码
复制代码
 1 /*
 2 *描述:筛素数法(倍数剔除、最小素因子筛选)对比
 3 *分析:倍数剔除:一个素数的倍数必须不是素数,即从2开始,将所以2的倍数去掉,然后从3开始,将3的倍数去掉,依次进行下去即可
 4 *       最小素因子筛选:简单的筛素数法(倍数剔除)是利用一个素数的倍数必须不是素数,同样任何一个数与其它所有素数的乘积必然也不是素数(这是因为每个合数必有一个最小素因子)。
 5                        要求是让每个合数仅被它的最小素因子筛去一次;即如果它是该素数的倍数那么它就不能再与素数表中该素数之后的素数相乘了。
 6 *
 7 *
 8 */
 9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <memory.h>
12 #include <time.h>
13 #include <math.h>
14 const int MAXN = 100000000;
15 bool flag[MAXN];
16 int primes[MAXN / 3], pi;
17 // 利用对每个素数的倍数必定不是素数来筛选
18 void GetPrime_1()
19 {
20     int i, j;
21     pi = 0;
22     memset(flag, false, sizeof(flag));
23     for (i = 2; i < MAXN; i++)
24         if (!flag[i])
25         {
26             primes[pi++] = i;
27             for (j = i; j < MAXN; j += i)
28                 flag[j] = true;
29         }
30 }
31 // 利用了每个合数必有一个最小素因子来筛选
32 void GetPrime_2()
33 {
34     int i, j;
35     pi = 0;
36     memset(flag, false, sizeof(flag));
37     for (i = 2; i < MAXN; i++)
38     {
39         if (!flag[i])
40             primes[pi++] = i;
41         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
42         {
43             flag[i * primes[j]] = true;
44             if (i % primes[j] == 0)
45                 break;
46         }
47     }
48 }
49 int main()
50 {
51     printf(" 在%d的数据量下普通的筛素数方法与改进之后的效率对比\n", MAXN);
52     clock_t clockBegin, clockEnd;
53     
54     clockBegin = clock();
55     GetPrime_1();
56     clockEnd = clock();
57     printf("普通的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
58     
59     clockBegin = clock();
60     GetPrime_2();
61     clockEnd = clock();
62     printf("改进的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
63     system("pause");
64     return 0;
65 }
复制代码
复制代码

具体的运行结果如下:

 

总结:

  1.普通的筛素数的原理是一个素数的倍数必须不是素数。

  2.改进的筛素数的原理是每个合数必有一个最小素因子,根据每个最小素因子去访问合数就能防止合数被重复访问。

我是天王盖地虎的分割线                                                                     

 

 

参考:http://www.cnblogs.com/xymqx/p/3718276.html

 

作者: 我爱物联网 
出处: http://yydcdut.cnblogs.com/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。



本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3876195.html,如需转载请自行联系原作者
相关文章
|
13天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
阿里云与企业共筑容器供应链安全
171329 12
|
16天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
150295 32
|
24天前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201960 14
对话 | ECS如何构筑企业上云的第一道安全防线
|
6天前
|
存储 人工智能 安全
对话|无影如何助力企业构建办公安全防护体系
阿里云无影助力企业构建办公安全防护体系
1251 8
|
2天前
|
机器学习/深度学习 自然语言处理 PyTorch
深入剖析Transformer架构中的多头注意力机制
多头注意力机制(Multi-Head Attention)是Transformer模型中的核心组件,通过并行运行多个独立的注意力机制,捕捉输入序列中不同子空间的语义关联。每个“头”独立处理Query、Key和Value矩阵,经过缩放点积注意力运算后,所有头的输出被拼接并通过线性层融合,最终生成更全面的表示。多头注意力不仅增强了模型对复杂依赖关系的理解,还在自然语言处理任务如机器翻译和阅读理解中表现出色。通过多头自注意力机制,模型在同一序列内部进行多角度的注意力计算,进一步提升了表达能力和泛化性能。
|
7天前
|
人工智能 自然语言处理 程序员
通义灵码2.0全新升级,AI程序员全面开放使用
通义灵码2.0来了,成为全球首个同时上线JetBrains和VSCode的AI 程序员产品!立即下载更新最新插件使用。
1275 23
|
8天前
|
机器学习/深度学习 自然语言处理 搜索推荐
自注意力机制全解析:从原理到计算细节,一文尽览!
自注意力机制(Self-Attention)最早可追溯至20世纪70年代的神经网络研究,但直到2017年Google Brain团队提出Transformer架构后才广泛应用于深度学习。它通过计算序列内部元素间的相关性,捕捉复杂依赖关系,并支持并行化训练,显著提升了处理长文本和序列数据的能力。相比传统的RNN、LSTM和GRU,自注意力机制在自然语言处理(NLP)、计算机视觉、语音识别及推荐系统等领域展现出卓越性能。其核心步骤包括生成查询(Q)、键(K)和值(V)向量,计算缩放点积注意力得分,应用Softmax归一化,以及加权求和生成输出。自注意力机制提高了模型的表达能力,带来了更精准的服务。
|
6天前
|
消息中间件 人工智能 运维
1月更文特别场——寻找用云高手,分享云&AI实践
我们寻找你,用云高手,欢迎分享你的真知灼见!
521 22
1月更文特别场——寻找用云高手,分享云&AI实践
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
|
12天前
|
人工智能 自然语言处理 API
阿里云百炼xWaytoAGI共学课DAY1 - 必须了解的企业级AI应用开发知识点
本课程旨在介绍阿里云百炼大模型平台的核心功能和应用场景,帮助开发者和技术小白快速上手,体验AI的强大能力,并探索企业级AI应用开发的可能性。