运行示例

PS H:\Read\num\x64\Release> .\eulerSievePro
EulerSievePro: a method to find out all primes below the number that you specify here please: 1234567890

Only the sum of all primes needed [y/n](y as default):

Start to work out the sum of all primes below 1234567890...
62106578 primes found in 8687 milliseconds.

PS H:\Read\num\x64\Release> .\eulerSievePro
EulerSievePro: a method to find out all primes below the number that you specify here please: 123456789

Only the sum of all primes needed [y/n](y as default):

Start to work out the sum of all primes below 123456789...
7027260 primes found in 828 milliseconds.

PS H:\Read\num\x64\Release> .\eulerSievePro
EulerSievePro: a method to find out all primes below the number that you specify here please: 12345678

Only the sum of all primes needed [y/n](y as default):

Start to work out the sum of all primes below 12345678...
809227 primes found in 94 milliseconds.

PS H:\Read\num\x64\Release>

对比用C++实现的Euler筛法程序里的eulerSieve和用C++实现的增强Eratosthenes筛法程序里的eSievePro,eulerSieve的性能优于eulerSieve;而eulerSievePro与eSievePro相比则互有优劣,在千万这个数量级eSievePro优于eulerSievePro,在亿级和十亿级eulerSievePro则要优于eSievePro。

增强Euler筛法的C++程序实现

为说明方便,把用C++实现的Euler筛法程序里的实现称为eulerSieve,而把这里的新实现称为eulerSievePro。

宏定义和全局量定义

1 typedef unsigned char u8;
2 //typedef uint64_t ulong;
3 typedef unsigned long ulong;
4 static std::vector<ulong> s_vecPrime;

main函数实现

 1 int main()
2 {
3 printf(" EulerSievePro: a method to find out all primes below the number that you specify here please: ");
4 std::string strInput;
5 getline(std::cin, strInput);
6 ulong raw_last = 0;
7 if (!str2num(strInput, raw_last))
8 return 0;
9 printf("\n Only the sum of all primes needed [y/n](y as default): ");
10 getline(std::cin, strInput);
11 bool bDetail = (strInput == "n");
12 if (bDetail)
13 std::cout << std::endl << " Start to work out all primes below " << raw_last << "...\n";
14 else
15 std::cout << std::endl << " Start to work out the sum of all primes below " << raw_last << "...\n";
16 if (!eulerSievePro(raw_last))
17 return 0;
18 if (bDetail)
19 showDetails();
20 return 0;
21 }

eulerSievePro函数实现

 1 bool eulerSievePro(ulong raw_last)
2 {
3 DWORD tickBegin = GetTickCount();
4 ulong last = raw_last / 2;
5 u8* pOdd = new u8[last];
6 if (!pOdd) {
7 printf("Lack of memory.\n");
8 return false;
9 }
10
11 ulong sum = 1;
12 ulong uplimit = 0;
13 s_vecPrime.push_back(2);
14 memset(pOdd, 1, last);
15 for (ulong halfIdx = 1; halfIdx < last; ++halfIdx) {
16 ulong num = (halfIdx + halfIdx) + 1;
17 if (pOdd[halfIdx] == 1) {
18 ++sum;
19 s_vecPrime.push_back(num);
20 }
21 for (ulong idx = 1; idx < sum; ++idx) {
22 if (uplimit != 0 && idx >= uplimit)
23 break;
24 ulong prime = s_vecPrime[idx];
25 ulong multiple = num * prime;
26 if (multiple >= raw_last) {
27 uplimit = idx;
28 break;
29 }
30 pOdd[multiple / 2] = 0;
31 if (num % prime == 0)
32 break;
33 }
34 }
35 std::cout <<" " << sum << " primes found in " << GetTickCount() - tickBegin << " milliseconds.\n\n";
36 delete []pOdd;
37 return true;
38 }

用C++实现的Euler筛法程序里的eulerSieve函数实现相比,这里的eulerSievePro函数做了以下几方面的优化:

1、pOdd的动态申请的空间是s_pAll的一半,既节省了存储空间,又节省了全体偶数的筛去过程;

2、外层循环里,halfIdx的步长为1,对应的num变量的步长则为2,因为只需要用奇数去筛就可以;

3、引入了uplimit变量,动态控制乘法运算的分量上界,可以大为减少乘法运算的总次数。

增强Euler筛法示例说明

以筛出100以内(不含100)的所有素数为例来具体说明一下本程序实现的增强Euler筛法。

构建一个下标k(即代码里的halfIdx)由0到[100/2]-1的数组,下标k对应的数组单元记录奇数2k+1是否为素数,一开始数组全体单元的值都为1,即所有奇数都标记为素数。并构建一个素数动态队列,把2加入其中。

从数组下标1(对应奇数3)开始遍历数组单元,3被记录为素数,于是把3加入素数队列,接着开始用3筛选合数,素数队列里打头的2不参与合数筛选,这时会筛去3*3(即9),程序里的具体实现是把奇数9在数组中对应单元(下标为[9/2]=4)的值置为0,以表达9不是素数。

数组下标2对应单元的值为1,把对应的奇数5加进素数队列,随后筛去5*3(即15)和5*5(即25)。

数组下标3对应单元的值为1,把对应奇数7加进素数队列,随后依次筛掉7*3(即21)、7*5(即35)和7*7(即49)。

遍历到数组下标4时,其对应单元的值为0,对应的奇数9不会加入素数队列,这时会筛掉9*3(即27),但因为判断出9是3的倍数,随后就不会用9进一步去筛掉9*5(即45)。

数组下标5对应单元的值为1,把对应奇数11加进素数队列,随后依次筛去11*3(即33)、11*5(即55)和11*7(即77)。11*11(即121)因大于100而不做处理,此时把uplimit置为11。

数组下标6对应单元的值为1,把对应的奇数13加进素数队列,随后依次筛去13*3(即39)、13*5(即65)、13*7(即91)。13*11这一次乘法运算不会实施,因为当前内部遍历到的素因数11和uplimit值相等(内部的机制是此前11*11已经大于100,此次的13*11必然也大于100)。

数组下标7对应单元的值为0,对应的奇数15不会加进素数队列,这时会筛去15*3(即45),因为15是3的倍数,随后不会继续筛去15*5。

数组下标8对应单元的值为1,把对应的奇数17加进素数队列,随后依次筛去17*3(即51)和17*5(即85)。17*7(即119)因为大于100而不做处理,此时uplimit的值调整为7。

数组下标为9对应单元的值为1,把对应的奇数19加进素数队列,随后依次筛去19*3(即57)和19*5(即95)。因为uplimit为7,不需要再去计算19*7并判断其结果是否大于100。

数组下标为10对应单元的值为0,对应的奇数21为合数,随后会筛去21*3(即63)。

之后23进素数队列,依次筛去23*3和23*5。

25能筛去25*3,25*5大于100,uplimit调整为5。

27能筛去27*3。

29进素数队列,并筛去29*3。

31进素数队列,并筛去31*3。

33能筛去33*3(即99)。

35,因为35*3大于100,不能筛去任何数,此时uplimit调整为3。至此,筛查范围内的所有合数都已被筛除,剩下的遍历只是把剩余的素数加到素数队列。

辅助函数str2num和showDetails

showDetails的实现和用C++实现的Euler筛法程序里完全一样。

 1 bool str2num(const std::string& str, ulong& val)
2 {
3 if (8 == sizeof(ulong)) {
4 if (str > "8589934592") {
5 printf("\n Invalid input - the biggest number could be 2^33.\n");
6 return false;
7 }
8 }
9 else {
10 if (str >= "4294967296") {
11 printf("\n Invalid input - the biggest number could be 2^32 - 1.\n");
12 return false;
13 }
14 }
15 size_t len = str.length();
16 val = 0;
17 for (size_t idx = 0; idx < len; ++idx) {
18 char ch = str[idx];
19 if (ch > '9' || ch < '0') {
20 printf("\n Invalid input - with non-numeric character.\n");
21 return false;
22 }
23 val = val * 10 + (ch - '0');
24 }
25 if (val <= 2) {
26 printf("\n Invalid input - at least 3.\n");
27 return false;
28 }
29 return true;
30 }

str2num函数用于把交互输入的字符串转化为整数。为支持更大范围的素数筛选,程序提供了ulong类型的备用定义:

typedef uint64_t ulong

不过输入一个很大的数,现有的筛选实现内存开销会很大。

另外,经测试发现,输入同样一个32位内的大数(小于2的32次方),eulerSievePro实现程序中把ulong定义为32位无符号整数比把ulong定义为64位无符号整数在处理性能上占显著优势。这应该和CPU的乘法运算实现有关,导致两个64位无符号数相乘会比两个32位无符号数相乘慢。

其他

https://github.com/readalps/EulerSievePro上放了eulerSievePro实现的源码文件,以及两个运行结果文件。

用C++实现的增强Euler筛法程序的更多相关文章

  1. 用C++实现的Euler筛法程序

    Euler筛法介绍 以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理. 和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批 ...

  2. 用C++实现的增强Eratosthenes筛法程序

    运行示例 PS H:\Read\num\x64\Release> .\eSievePro Eratosthenes sieve: a method to find out all primes ...

  3. 25个增强iOS应用程序性能的提示和技巧(高级篇)(2)

    25个增强iOS应用程序性能的提示和技巧(高级篇)(2) 2013-04-16 14:56 破船之家 beyondvincent 字号:T | T 在开发iOS应用程序时,让程序具有良好的性能是非常关 ...

  4. 25个增强iOS应用程序性能的提示和技巧(高级篇)(1)

    25个增强iOS应用程序性能的提示和技巧(高级篇)(1) 2013-04-16 14:56 破船之家 beyondvincent 字号:T | T 在开发iOS应用程序时,让程序具有良好的性能是非常关 ...

  5. 25个增强iOS应用程序性能的提示和技巧(中级篇)(3)

    25个增强iOS应用程序性能的提示和技巧(中级篇)(3) 2013-04-16 14:42 破船之家 beyondvincent 字号:T | T 本文收集了25个关于可以提升程序性能的提示和技巧,分 ...

  6. 25个增强iOS应用程序性能的提示和技巧(中级篇)(2)

    25个增强iOS应用程序性能的提示和技巧(中级篇)(2) 2013-04-16 14:42 破船之家 beyondvincent 字号:T | T 本文收集了25个关于可以提升程序性能的提示和技巧,分 ...

  7. 25个增强iOS应用程序性能的提示和技巧--中级篇

    25个增强iOS应用程序性能的提示和技巧--中级篇 标签: ios性能优化内存管理 2013-12-13 10:55 738人阅读 评论(0) 收藏 举报  分类: IPhone开发高级系列(34)  ...

  8. 25个增强iOS应用程序性能的提示和技巧(初级篇)

    25个增强iOS应用程序性能的提示和技巧(初级篇) 标签: ios内存管理性能优化 2013-12-13 10:53 916人阅读 评论(0) 收藏 举报  分类: IPhone开发高级系列(34)  ...

  9. 25个增强iOS应用程序性能的提示和技巧 — 中级篇

    本文由破船译自:raywenderlich 转载请注明出处:BeyondVincent的博客 _____________ 在开发iOS应用程序时.让程序具有良好的性能是非常关键的.这也是用户所期望的. ...

随机推荐

  1. P5311 [Ynoi2011] 成都七中

    P5311 [Ynoi2011] 成都七中 题意 给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作. 查询操作给定参数 \(l\ r\ x\),需输出: 将树中编号在 ...

  2. Odoo的附件大小限制

    Odoo使用binary类型来保存附件数据,可以直接支持附件数据的上传.但是在实际使用中,有可能遇到附件文件大小超过限制的情况,如下图: 但是ERP定制过程中难免会遇到客户确实需要上传超大附件,那么怎 ...

  3. Python基础之读取ini文件

    基本使用方法 第一步:准备一份INI文件.如test1.ini [ITEMS] item1=1 item2=2 item3=3 item4=4 [ITEM1] test1=aaa [ITEM2] te ...

  4. Python -- 值转换为字符串的两种机制

    可以通过以下两个函数来使用这两种机制:一是通过str函数,它会把值转换为合理形式的字符串,以便用户可以理解:而repr会创建一个字符串,它以合法的Python表达式的形式来表示值.下面是一些例子: & ...

  5. DC-2 靶机渗透测试

    DC-2 靶机渗透测试 冲冲冲,好好学习. 本靶机核心内容"受限shell提权",知识点在另一篇文章中总结归纳了. 攻击机:kali 靶 机:DC-2 准备:在使用前需要在操作机的 ...

  6. [考试总结]noip模拟33

    连炸两场... 伤心... 第一个题目首先因为有期望坐镇,然后跳过... 然后第二个题目发现题目挺绕的,然后转化了一句话题意,然后..... \(\huge{\text{转化错了!!!!}}\) 然而 ...

  7. icmp介绍以及arp攻击

    目录 一.ip数据包格式 二.ICMP协议介绍 三.ARP协议介绍 四.ARP攻击原理 一.ip数据包格式 网络层的功能: 定义了基于ip协议的逻辑地址 连接不同的媒介类型 选择是数据通过网络的最佳途 ...

  8. js原始数据类型有哪些,引用数据类型有哪些

    js的数据类型划分方式为 原始数据类型和 引用数据类型 栈: 原始数据类型(Undefined,Null,Boolean,Number.String) 堆: 引用数据类型(对象.数组.函数) 两种类型 ...

  9. 只要套路对,薪资直接翻一倍!保姆级Android面试葵花宝典,肝完面试犹如开挂

    跳槽,这在 IT 互联网圈是非常普遍的,也是让自己升职加薪,走上人生巅峰的重要方式.那么作为一个普通的Android程序猿,我们如何才能斩获大厂offer 呢? 疫情向好.面试在即,还在迷茫踌躇中的后 ...

  10. DL基础补全计划(六)---卷积和池化

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...