我使用非常简单的算法尝试了Project Euler的问题10,并且运行时间看起来像几个小时。所以我用Google搜索了一个有效的算法,然后通过Shlomif Fish找到了它。 代码转载如下:
int main(int argc, char * argv[])
{
int p, i;
int mark_limit;
long long sum = 0;
memset(bitmask, '\0', sizeof(bitmask));
mark_limit = (int)sqrt(limit);
for (p=2 ; p <= mark_limit ; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
/* It is a prime. */
sum += p;
for (i=p*p;i<=limit;i+=p)
{
bitmask[i>>3] |= (1 << (i&(8-1)));
}
}
}
for (; p <= limit; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
sum += p;
}
}
我在理解代码时遇到了问题。具体来说,这个位移代码如何能够确定数字是否为素数。
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
/* It is a prime. */
sum += p;
for (i=p*p;i<=limit;i+=p)
{
bitmask[i>>3] |= (1 << (i&(8-1)));
}
}
有人可以向我解释这个代码块,尤其是这部分( bitmask[p>>3]&(1 << (p&(8-1)
吗?非常感谢你。
答案 0 :(得分:3)
该代码是Eratosthenes的修改过的筛子。他将一个数字打包成一个位:0
= prime,1
=复合。位移是指到字节数组中的正确位。
bitmask[p>>3]
相当于
bitmask[p / 8]
选择bitmask[]
数组中的正确字节。
(p&(8-1))
等于p & 7
,它选择p
的低3位。这相当于p % 8
总的来说,我们正在选择字节(p % 8)
的位bitmask[p / 8]
。那就是我们选择bitmask[]
数组中代表数字p的位。
1 << (p % 8)
在一个字节中正确设置1
位。然后将其与bitmask[p / 8]
字节进行“与”运算,以查看是否设置了该特定位,从而检查p
是否为素数。
整体陈述等同于if (isPrime(p))
,使用已经完成的筛子部分来帮助延长筛子。
答案 1 :(得分:0)
位掩码充当位数组。由于无法单独寻址位,因此首先必须访问该字节,然后修改其中的位。向右移动3与除以8相同,这使您在正确的字节上。然后,其余的一个被移动到位。
x&gt;&gt; 3相当于x / 8
x&amp;(8-1)相当于x%8
但是在一些较旧的系统上,位操作可能更快。
该行设置第i位,其中我被确定为不是素数,因为它是另一个素数的倍数:
bitmask[i>>3] |= (1 << (i&(8-1)));
该行检查第p位是否未设置,这意味着它是素数,因为如果它不是素数,则它将由上面的行设置。
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )