1. 程式人生 > >求一千萬以內的素數的個數

求一千萬以內的素數的個數

問題描述:輸入n,輸出小於n的素數的個數,當n等於0時退出程式

輸入:整數n(n<10 000 000)

輸出:小於n的素數的個數,當n等於0時退出程式

首先我們知道,偶數一定不是素數(2除外)

所以我們可以這麼解決這道題:

用一千萬個標誌位表示對應數字是否為素數,剛開始時將其全部置為true,代表是素數。

然後進行篩選:2的倍數全部不是素數,將2的倍數變成false,3的倍數全都不是素數,將3的倍數變成false,4的倍數全都不是素數,將4的倍數變成false.。。。。

最後計算true的值就行了

優化:既然偶數全都不是素數,那就不用設定標誌位來設定他們了,這樣可以將標誌位佔用的記憶體大小減少一半

使用bit作為標誌位,而不是bool,這樣可以將記憶體使用量將為原來的1/8

/*
特色:
1.利用篩法,但是取消了對偶數位的儲存,例如記憶體中第一位是1,第二位是3,第三位是5
2.利用位(bit)作為儲存位置,而不是基本資料型別,節省記憶體
3.程式一開始就將所有素數找出,後續步驟只不過是:輸入-計數-輸出 而已
*/

#include<iostream>
#include<string.h>
#define Length 10000001
using std::cin;
using std::cout;
using std::endl;
//將a的des位置為1
inline void set(char* a, int des)
{
	char &op = a[des/8];
	int offset = des % 8;//0-7
	char tmp = 1;
	tmp = tmp << (7-offset);
	op = op | tmp;
}
int main()
{
	int num = 5000000 / 8 + 1;
	char *a = new char[num];
	memset(a, 0, num);

	for (int i = 3; i < (Length-1)/2; i += 2)
	for (int j = 3; (i*j - 1) / 2 < (Length-1)/2; j += 2)
		set(a, (i*j - 1) / 2);

	int n;
	while (cin >> n && n != 0)
	{
		if (n == 1){
			cout << "0" << endl;
			continue;
		}
		else if (n == 2){
			cout << "1" << endl;
			continue;
		}
		if (n % 2 == 0)
			n--;
		n = (n - 1) / 2;
		int count = 2;
		for (int i = 2; i <= n; i++)
		{
			if ((a[i / 8] & (1 << (7 - i % 8))) == 0)//為0的奇數位是素數
				count++;
		}

		cout << count << endl;
	}
}