#include <stdio.h>
#include <math.h>
void sieve(unsigned int up, unsigned int low, unsigned char primes[]);
main()
{
unsigned int low, up;
unsigned int steps;
scanf("%d",&steps);
for (unsigned int i=0;i<steps;i++){
scanf("%d %d",&low,&up);
unsigned char v[up-low];
sieve (up, low, v);
for(unsigned int j=0; j<up-low+1; j++){
if (v[j] == 1){
printf("%d\n",low+j);
}
}
}
}
//-------------------------------------------------------------------
void sieve(unsigned int up, unsigned int low, unsigned char primes[])
{
for (unsigned int i=0;i<up-low+1;i++){
primes[i]=1;
}
for (unsigned int i=2;i<sqrt(up+1);i++) {
for (int j=((low/i)*i)+i;j<up+1;j+=i){
primes[j-low] = 0;
}
}
}
我正在尝试查找特定范围内的素数。我正在使用Erastothenes的分段筛,但不幸的是它丢失了一些素数,这是因为:
for (int j=((low/i)*i)+i;j<up+1;j+=i){
primes[j-low] = 0;
当i
大于我的下限筛子功能时,开始用0
值标记素数,毕竟它们不在我的标准输出中。
例如stdin:
1
2 1000
例如stdout:
2
37它丢失了2到37之间的所有素数 41个
43个
......
通过算法总是将下限值识别为素数。
例如stdin:
4 10例如stdout:
4
5
7
我需要一些帮助来调整我的算法以正确标记这些数字,因为在几个小时之后我真的无能为什么条件让它起作用。
答案 0 :(得分:1)
首先,您有一个错误的错误。你的数组不够大,无法容纳所有元素的标志。把它做得更大:
unsigned char v[up-low+1];
现在主要问题出在你的循环中:
for (unsigned int i=2;i<sqrt(up+1);i++) {
for (int j=((low/i)*i)+i;j<up+1;j+=i){
primes[j-low] = 0;
}
}
您没有从正确的索引开始。在low==4
的情况下,内循环的第一次迭代将j
设置为((4/2)*2)+2 == (2*2)+2 == 4*2 == 6
,因此您将完全跳过4。
保持简单。在j
处开始i*2
。在循环中,跳过j
小于low
的任何值:
for (unsigned int i=2;i<sqrt(up+1);i++) {
for (unsigned int j=i*2;j<up+1;j+=i){
if (j < low) continue;
primes[j-low] = 0;
}
}
答案 1 :(得分:0)
您可以尝试分析我的c ++解决方案以获得分段筛选,因为网上没有很多分段筛分正确的实现。我希望它可以帮助你理解它是如何工作的。干杯!
void sito_delta( int delta, std::vector<int> &res)
{
std::unique_ptr<int[]> results(new int[delta+1]);
for(int i = 0; i <= delta; ++i)
results[i] = 1;
int pierw = sqrt(delta);
for (int j = 2; j <= pierw; ++j)
{
if(results[j])
{
for (int k = 2*j; k <= delta; k+=j)
{
results[k]=0;
}
}
}
for (int m = 2; m <= delta; ++m)
if (results[m])
{
res.push_back(m);
std::cout<<","<<m;
}
};
void sito_segment(int n,std::vector<int> &fiPri)
{
int delta = sqrt(n);
if (delta>10)
{
sito_segment(delta,fiPri);
// COmpute using fiPri as primes
// n=n,prime = fiPri;
std::vector<int> prime=fiPri;
int offset = delta;
int low = offset;
int high = offset * 2;
while (low < n)
{
if (high >=n ) high = n;
int mark[offset+1];
for (int s=0;s<=offset;++s)
mark[s]=1;
for(int j = 0; j< prime.size(); ++j)
{
int lowMinimum = (low/prime[j]) * prime[j];
if(lowMinimum < low)
lowMinimum += prime[j];
for(int k = lowMinimum; k<=high;k+=prime[j])
mark[k-low]=0;
}
for(int i = low; i <= high; i++)
if(mark[i-low])
{
fiPri.push_back(i);
std::cout<<","<<i;
}
low=low+offset;
high=high+offset;
}
}
else
{
std::vector<int> prime;
sito_delta(delta, prime);
//
fiPri = prime;
//
int offset = delta;
int low = offset;
int high = offset * 2;
// Process segments one by one
while (low < n)
{
if (high >= n) high = n;
int mark[offset+1];
for (int s = 0; s <= offset; ++s)
mark[s] = 1;
for (int j = 0; j < prime.size(); ++j)
{
// find the minimum number in [low..high] that is
// multiple of prime[i] (divisible by prime[j])
int lowMinimum = (low/prime[j]) * prime[j];
if(lowMinimum < low)
lowMinimum += prime[j];
//Mark multiples of prime[i] in [low..high]
for (int k = lowMinimum; k <= high; k+=prime[j])
mark[k-low] = 0;
}
for (int i = low; i <= high; i++)
if(mark[i-low])
{
fiPri.push_back(i);
std::cout<<","<<i;
}
low = low + offset;
high = high + offset;
}
}
};
int main()
{
std::vector<int> fiPri;
sito_segment(1013,fiPri);
}