首页 > 编程语言 > 详细

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

时间:2021-01-19 23:38:41      阅读:41      评论:0      收藏:0      [点我收藏+]

Euler筛法介绍

以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理。

和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批全部筛掉,而Euler筛法用2筛时仅仅把2*2(即4)筛掉,而把其它偶数留到后面再筛掉,从而避免了一个偶数被多次筛除带来的性能开销,比如偶数6、8、10,在随后用3、4、5筛的时候会被筛掉。

Euler筛法引入了一个素数队列,从2开始没被筛掉的数会依次加进素数队列,当用3筛时,素数队列里有2和3两个素数,这时会筛掉3*2(即6)和3*3(即9)。

当用4筛时,4因为之前被2筛掉了,所以4不会加进素数队列,此时素数队列里依然只有2和3两个素数,这时会筛掉4*2(即8),但4*3(即12)并不在这时筛掉,这是因为4本身是素数2的倍数,即4*3里不能保证3是最小素因数。

当用5筛时,先把5加入素数队列,随后筛掉5*2(即10)、5*3(即15)和5*5(即25)。

当用6筛时,6因为之前被3筛掉了,所以此时素数队列里依然只有2、3、5,这时会筛掉6*2(即12),但因为判断出6是2的倍数,随后就不会用6进一步去筛掉6*3(即18)。

当用7筛时,先把7加入素数队列,随后依次筛掉7*2(即14)、7*3(即21)、7*5(即35)和7*7(即49)。

当用8筛时,8因为之前被4筛掉了,所以此时素数队列里依然只有2、3、5、7,这时会筛掉8*2(即16),但因为判断出8是2的倍数,随后就不会用8进一步去筛掉8*3(即24)。

当用9筛时,9因为之前被3筛掉了,所以此时素数队列里依然只有2、3、5、7,这时会筛掉9*2(即18)和9*3(即27),但因为判断出9是3的倍数,随后就不会用9进一步去筛掉9*5(即45)。

当用10筛时,10因为之前被5筛掉了,所有此时素数队列里依然是2、3、5、7,这时会筛掉10*2(即20),但因为10是2的倍数,随后不会用10去筛掉10*3(即30)。

当用11筛时,先把11加入素数队列,随后依次筛掉11*2(即22),11*3(即33),11*5(即55),11*7(即77)。11*11(即121)因为大于100而不在筛查范围。

用12筛,只会筛去12*2。

用13筛,13进素数队列,随后依次筛去13*2,13*3,13*5,13*7。13*11不在筛查范围。

用14、15、16筛,依次会筛去14*2、15*2和15*3、16*2。

用17筛,17进素数队列,随后依次筛去17*2、17*3、17*5。17*7不在筛查范围。

……

用49筛,会筛去49*2。49*3不在筛查范围。

用50筛,会筛去50*2。50*3不在筛查范围。

用51筛,不会筛去任何数,因为51*2>100。

随后用52、53、……、99、100筛的过程里,都不再会筛去任何数,而只有素数进素数队列的行为。

由上述过程可知,欧拉筛法的核心思路是:对于筛查范围内的任意一个合数m,只使用m中除m之外最大的因数把m筛去。例如,45=3*3*5,确保用15筛去45即可。更一般的情形,m=p1*p2*……*ps,其中p1、p2、……、ps均为素数且满足p1<=p2<=……<=ps,则确保用p2*……*ps筛去m即可。

Euler筛法的C++程序实现

宏定义和全局量定义

1 typedef unsigned char u8;
2 typedef unsigned long ulong;
3 static ulong s_last = 0;
4 static u8* s_pAll = NULL;
5 static std::vector<ulong> s_vecPrime;

和Eratosthenes筛法实现的定义完全一样。

main函数实现

 1 int main()
 2 {
 3     printf(" EulerSieve: 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     s_last = strtoul(strInput.c_str(), 0, 10);
 7     if (s_last <= 2) {
 8         printf("\n Wrong input.\n");
 9         return 0;
10     }
11     printf("\n Only the sum of all primes needed [y/n](y as default): ");
12     getline(std::cin, strInput);
13     bool bDetail = (strInput == "n");
14     if (bDetail)
15         printf("\n Start to work out all primes below %u...\n", s_last);
16     else
17         printf("\n Start to work out the sum of all primes below %u...\n", s_last);
18     if (!eulerSieve())
19         return 0;
20     if (bDetail)
21         showDetails();
22     return 0;
23 }

eulerSieve函数实现

 1 bool eulerSieve()
 2 {
 3     DWORD tickBegin = GetTickCount();
 4     s_pAll = new u8[s_last];
 5     if (!s_pAll) {
 6         printf("Lack of memory.\n");
 7         return false;
 8     }
 9 
10     ulong sum = 0;
11     memset(s_pAll, 1, s_last);
12     for (ulong num = 2; num < s_last; ++num) {
13         if (s_pAll[num - 1] == 1) {
14             ++sum;
15             s_vecPrime.push_back(num);
16         }
17         for (ulong idx = 0; idx < sum; ++idx) {
18             ulong prime = s_vecPrime[idx];
19             ulong multiple = num * prime;
20             if (multiple >= s_last)
21                 break;
22             s_pAll[multiple - 1] = 0;
23             if (num % prime == 0)
24                 break;
25         }
26     }
27     printf(" %u primes found in %u milliseconds.\n\n", sum, GetTickCount() - tickBegin);
28     delete []s_pAll;
29     return true;
30 }

showDetails函数实现和Eratosthenes筛法里的实现完全一样。

运行示例

PS H:\Read\num\x64\Release> .\eulerSieve
EulerSieve: 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 15734 milliseconds.

PS H:\Read\num\x64\Release> .\eulerSieve
EulerSieve: 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 1391 milliseconds.

PS H:\Read\num\x64\Release> .\eulerSieve
EulerSieve: 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 141 milliseconds.

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

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

Start to work out all primes below 100...
25 primes found in 0 milliseconds.

2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
PS H:\Read\num\x64\Release>

对比用C++实现的Eratosthenes筛法程序里的eSieve和用C++实现的增强Eratosthenes筛法程序里的eSievePro,eulerSieve的性能优于eSieve,但不如eSievePro。

其他

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

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

原文:https://www.cnblogs.com/readalps/p/14294618.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!