redraiment在家极度无聊,于是找了张纸开始统计素数的个数。
设函数f(n)返回从1->n之间素数的个数。
redraiment发现:
f(1) = 0
f(10) = 4
f(100) = 25
...
满足g(m) = 17 * m2 / 3 - 22 * m / 3 + 5 / 3
其中m为n的位数。
他很激动,是不是自己发现了素数分布的规律了!
请你设计一个程序,求出1->n范围内素数的个数,来验证redraiment是不是正确的,也许还可以得诺贝尔奖呢。^_^
输入包括多组数据。
每组数据仅有一个整数n (1≤n≤100000000)。
输入以0结束
对于每组数据输入,输出一行,为1->n(包括n)之间的素数的个数。
输入:
1
10
65
100
0
输出:
0
4
18
25
附上源代码
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000000
unsigned char isPrime[(MAX / 8) + 1]; // 使用位数组压缩空间
long primeCount[MAX + 1]; // 存储每个数的素数个数
// 判断某个数是否为素数(通过位操作)
bool getPrime(long i) {
return isPrime[i / 8] & (1 << (i % 8));
}
// 设置某个数为合数(通过位操作)
void setComposite(long i) {
isPrime[i / 8] &= ~(1 << (i % 8));
}
// 埃拉托色尼筛法并预处理素数个数
void sieve() {
// 初始化所有数为素数
memset(isPrime, 0xFF, sizeof(isPrime)); // 将数组初始化为全1
long i = 0;
for (; i <= MAX; i++) {
isPrime[i / 8] |= (1 << (i % 8));
}
// 埃拉托色尼筛法
long iNsqrt = sqrt(MAX);
long in = 2;
for (; in <= iNsqrt; in++) {
if (getPrime(in)) {
long j = in * in;
for (; j <= MAX; j += in) {
setComposite(j);
}
}
}
// 预处理每个数的素数个数
long ind = 2;
for (; ind <= MAX; ind++) {
primeCount[ind] = primeCount[ind - 1] + (getPrime(ind) ? 1 : 0);
}
}
// 判断一个数是否为质数
int Isprime(int num) {
if (num < 2) return 0; // 小于2的数不是质数
if (num == 2) return 1; // 2是质数
if (num % 2 == 0) return 0; // 其他偶数不是质数
int iNum = 3;
long inum = sqrt(num);
for (; iNum <= inum; iNum += 2) { // 只检查奇数因子
if (num % iNum == 0) return 0;
}
return 1; // 是质数
}
int main() {
sieve(); // 预处理MAX所有素数
long iNum;
while (scanf("%ld", &iNum) != EOF && iNum > 0) {
if (iNum <= MAX) {
printf("%ld\n", primeCount[iNum]);
} else {
long index = MAX + 1;
long iNum3 = 0;
for (; index <= iNum; index++) { // 修正循环条件
if (Isprime(index)) iNum3++;
}
printf("%ld\n", (primeCount[MAX] + iNum3));
}
}
return 0;
}