C 投影欧拉问题10-高效算法

C 投影欧拉问题10-高效算法,c,C,我尝试了Project Euler的问题10,使用了非常简单的算法,运行时间看起来像几个小时。所以我在谷歌上搜索了一个有效的算法,并通过。 代码复制如下: 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);

我尝试了Project Euler的问题10,使用了非常简单的算法,运行时间看起来像几个小时。所以我在谷歌上搜索了一个有效的算法,并通过。 代码复制如下:

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;
        }
    }
intmain(intargc,char*argv[])
{
int p,i;
int标记_限制;
长和=0;
memset(位掩码,'\0',sizeof(位掩码));
mark_limit=(int)sqrt(limit);

对于(p=2;p>3)&(13)|=(13)&(1>3)&(13)|=(1>3)]&(1位掩码充当一个位数组。由于不能单独寻址位,因此必须先访问字节,然后修改其中的一位。右移3等于除以8,这将使您位于正确的字节。然后,将一位移到适当的位置,再将余数移到适当的位置

x> >3相当于x/8

x&(8-1)相当于x%8

但在一些较旧的系统上,位操作可能更快

该行设置第i位,其中i被确定为非素数,因为它是另一个素数的倍数:

bitmask[i>>3] |= (1 << (i&(8-1)));

bitmask[i>>3]|=(1该代码是一个经过修改的Eratosthenes筛。他将一个数字压缩成一个位:
0
=prime,
1
=composite。位移位是为了在字节数组中找到正确的位

 bitmask[p>>3]
相当于

 bitmask[p / 8]
它在
位掩码[]
数组中选择正确的字节

(p&(8-1))
等于
p&7
,它选择
p
的较低3位。这相当于
p%8

总的来说,我们正在选择字节
位掩码[p/8]
的位
(p%8)
。也就是说,我们正在
位掩码[]
数组中选择表示数字p的位


1位操作从来没有更快过。最早的C编译器能够自动完成。大多数编译器即使在优化关闭的情况下也能完成。@Dietrich Epp实际上还有很多编译器无法完成优化,除非明确要求。如果程序性能至关重要(只有这样),而且代码应该是可移植的,优化“轮班分工”可能是个好主意手动,即使它使代码变得丑陋,而且远不如可读。@ Lundin:这有点令人惊讶。你能给出任何例子吗?@沃恩:那么X/8和X% 8如何能够确定素数吗?这样你就可以用BIT或向量(专门容器)在C++中得到相同的打包。没有位技巧。即使在C语言中,你也应该使用抽象从位到数组的映射的函数。编写这样的代码是不好的风格。你能进一步解释为什么使用“8”吗?p可以大得多,比如100000。8有什么特别之处,它被用作“基”在这些位移位中?还有,为什么
1@Standstill,筛是一个逻辑位数组。如果位
N
为on或true,则数字
N
为素数。这些位被实现为8位字节数组。这就是神奇数字8的来源。筛可以同样轻松地用16/32/64位元素实现在这种情况下,常数将被更改为匹配。位移位和屏蔽操作用于寻址所需的字节,然后寻址其中的特定位。@STANDSTART:@BLASTBURN是正确的,
8
是一个字节中的位数。手动从
p=5
p=11
通过一些示例来了解f或其他。ANDing是检查
位掩码[p/8]中的位
已设置:
1&1=1
0&1=0
。该位标志着
p
是否为素数。我建议您仔细阅读Eratosthenes的筛选。编写您自己的更简单的实现,这将帮助您了解这里的代码在做什么。谢谢。我认为这些信息足以让我进行研究。
 bitmask[p / 8]
(p&(8-1))