项目欧拉问题10 - 高效算法

时间:2011-09-28 05:27:31

标签: c

我使用非常简单的算法尝试了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)吗?非常感谢你。

2 个答案:

答案 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))) ) )